diff --git a/package-lock.json b/package-lock.json
index bac8be1..378a250 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -19,6 +19,7 @@
"docusaurus-plugin-image-zoom": "^2.0.0",
"echarts": "^5.5.1",
"echarts-for-react": "^3.0.2",
+ "jquery": "^3.7.1",
"katex": "^0.16.11",
"prism-react-renderer": "^2.3.1",
"react": "^18.3.1",
@@ -8732,6 +8733,11 @@
"@sideway/pinpoint": "^2.0.0"
}
},
+ "node_modules/jquery": {
+ "version": "3.7.1",
+ "resolved": "https://registry.npmjs.org/jquery/-/jquery-3.7.1.tgz",
+ "integrity": "sha512-m4avr8yL8kmFN8psrbFFFmB/If14iN5o9nw/NgnnM+kybDJpRsAynV2BsfpTYrTRysYUdADVD7CkUUizgkpLfg=="
+ },
"node_modules/js-tokens": {
"version": "4.0.0",
"resolved": "https://registry.npmmirror.com/js-tokens/-/js-tokens-4.0.0.tgz",
diff --git a/package.json b/package.json
index d117f73..6c06686 100644
--- a/package.json
+++ b/package.json
@@ -25,6 +25,7 @@
"docusaurus-plugin-image-zoom": "^2.0.0",
"echarts": "^5.5.1",
"echarts-for-react": "^3.0.2",
+ "jquery": "^3.7.1",
"katex": "^0.16.11",
"prism-react-renderer": "^2.3.1",
"react": "^18.3.1",
diff --git a/src/components/DevLeaderboard/Details.js b/src/components/DevLeaderboard/Details.js
new file mode 100644
index 0000000..465f078
--- /dev/null
+++ b/src/components/DevLeaderboard/Details.js
@@ -0,0 +1,101 @@
+import React, { useEffect, useState } from "react";
+import "./devLeaderboard.css";
+
+const Details = ({ graph, id, month, typeMap, platform }) => {
+ const [details, setDetails] = useState([]);
+
+ useEffect(() => {
+ if (graph && id) {
+ const data = graph.data[month];
+ const selfNode = data.nodes.find(
+ (node) => graph.meta.nodes[node[0]][0] === id
+ );
+ const detailsData = [];
+
+ if (selfNode) {
+ detailsData.push([
+ "Self",
+ graph.meta.retentionFactor,
+ selfNode[1],
+ (graph.meta.retentionFactor * selfNode[1]).toFixed(3),
+ ]);
+
+ const otherDetails = data.links
+ .filter((link) => graph.meta.nodes[link[1]][0] === id)
+ .map((link) => {
+ const sourceIndex = link[0];
+ const sourceNode = graph.meta.nodes[sourceIndex];
+ const sourceValue = data.nodes.find(
+ (node) => node[0] === sourceIndex
+ );
+ const type = typeMap.get(sourceNode[0][0]);
+ let name = sourceNode[1];
+ if (type === "pull")
+ name = "#" + sourceNode[0].slice(1) + " " + sourceNode[1];
+ else if (type === "issue")
+ name =
+ "#" +
+ (platform === "gitee"
+ ? parseInt(sourceNode[0].slice(1)).toString(36).toUpperCase()
+ : sourceNode[0].slice(1)) +
+ " " +
+ sourceNode[1];
+ return [
+ name,
+ parseFloat((1 - graph.meta.retentionFactor) * link[2]).toFixed(3),
+ sourceValue[2],
+ parseFloat(
+ (
+ (1 - graph.meta.retentionFactor) *
+ link[2] *
+ sourceValue[2]
+ ).toFixed(3)
+ ),
+ ];
+ })
+ .sort((a, b) => b[3] - a[3]);
+
+ const repoNode = data.nodes.find((node) => node[0] === 0);
+ otherDetails.push([
+ graph.meta.repoName,
+ (1 / (data.nodes.length - 1)).toFixed(3),
+ repoNode[2],
+ ((1 / (data.nodes.length - 1)) * repoNode[2]).toFixed(3),
+ ]);
+
+ setDetails([...detailsData, ...otherDetails]);
+ }
+ }
+ }, [graph, id, month, typeMap, platform]);
+
+ return (
+
+
+
Details
+
+
+
+
+
+ From |
+ Ratio |
+ Value |
+ OpenRank |
+
+
+
+ {details.map((detail, index) => (
+
+ {detail.map((d, i) => (
+ {d} |
+ ))}
+
+ ))}
+
+
+
+
+ );
+};
+
+export default Details;
\ No newline at end of file
diff --git a/src/components/DevLeaderboard/Graph.js b/src/components/DevLeaderboard/Graph.js
new file mode 100644
index 0000000..0e56156
--- /dev/null
+++ b/src/components/DevLeaderboard/Graph.js
@@ -0,0 +1,103 @@
+import React, { useEffect, useState } from "react";
+import * as echarts from "echarts";
+import "./devLeaderboard.css";
+
+const Graph = ({
+ graph,
+ month,
+ repoName,
+ platform,
+ typeMap,
+ onNodeDblClick,
+}) => {
+ useEffect(() => {
+ if (graph) {
+ const container = document.getElementById("graph");
+ const chart = echarts.init(container);
+
+ const nodes = graph.data[month].nodes.map((node) => {
+ const id = graph.meta.nodes[node[0]][0];
+ const type = typeMap.get(id[0]);
+ let name = graph.meta.nodes[node[0]][1];
+ if (type === "pull") name = "#" + id.slice(1);
+ else if (type === "issue")
+ name =
+ "#" +
+ (platform === "gitee"
+ ? parseInt(id.slice(1)).toString(36).toUpperCase()
+ : id.slice(1));
+ return {
+ id,
+ initialValue: node[1],
+ value: node[2],
+ name,
+ symbolSize: Math.log(node[2] + 1) * 10,
+ category: type,
+ };
+ });
+
+ const links = graph.data[month].links.map((link) => ({
+ source: graph.meta.nodes[link[0]][0],
+ target: graph.meta.nodes[link[1]][0],
+ value: link[2],
+ }));
+
+ nodes.forEach((node) => {
+ if (node.category === "issue" || node.category === "pull") {
+ links.push({
+ source: graph.meta.nodes[0][0],
+ target: node.id,
+ value: 0.05,
+ });
+ }
+ });
+
+ const categories = Array.from(typeMap.values());
+
+ const option = {
+ title: {
+ text: `Community OpenRank for ${repoName} in ${month}`,
+ top: "bottom",
+ left: "right",
+ },
+ legend: [{ data: categories }],
+ tooltip: { trigger: "item" },
+ series: [
+ {
+ name: "Collaborative graph",
+ type: "graph",
+ layout: "force",
+ nodes,
+ links,
+ categories: categories.map((c) => ({ name: c })),
+ roam: true,
+ label: {
+ position: "right",
+ show: true,
+ },
+ force: {
+ layoutAnimation: false,
+ repulsion: 300,
+ },
+ },
+ ],
+ };
+
+ chart.setOption(option);
+ chart.on("dblclick", (params) => onNodeDblClick(params.data.id));
+
+ return () => {
+ chart.dispose();
+ };
+ }
+ }, [graph, month, repoName, platform, typeMap, onNodeDblClick]);
+
+ return (
+
+ );
+};
+
+export default Graph;
diff --git a/src/components/DevLeaderboard/Leaderboard.js b/src/components/DevLeaderboard/Leaderboard.js
new file mode 100644
index 0000000..820c29b
--- /dev/null
+++ b/src/components/DevLeaderboard/Leaderboard.js
@@ -0,0 +1,51 @@
+import React, { useEffect, useState } from "react";
+import * as echarts from "echarts";
+import $ from "jquery";
+import "./devLeaderboard.css";
+
+const Leaderboard = ({ graph, month }) => {
+ const [users, setUsers] = useState([]);
+
+ useEffect(() => {
+ if (graph) {
+ const sortedUsers = graph.data[month].nodes
+ .map((node) => ({
+ id: graph.meta.nodes[node[0]][0],
+ login: graph.meta.nodes[node[0]][1],
+ value: node[2],
+ }))
+ .filter((user) => user.id[0] === "u")
+ .sort((a, b) => b.value - a.value);
+
+ setUsers(sortedUsers);
+ }
+ }, [graph, month]);
+
+ return (
+
+
+
Leaderboard
+
+
+
+
+
+ Login |
+ OpenRank |
+
+
+
+ {users.map((user, index) => (
+
+ {user.login} |
+ {user.value} |
+
+ ))}
+
+
+
+
+ );
+};
+
+export default Leaderboard;
diff --git a/src/components/DevLeaderboard/devLeaderboard.css b/src/components/DevLeaderboard/devLeaderboard.css
new file mode 100644
index 0000000..add22ba
--- /dev/null
+++ b/src/components/DevLeaderboard/devLeaderboard.css
@@ -0,0 +1,68 @@
+#main {
+ display: flex;
+}
+
+#graph {
+ height: 800px;
+}
+
+.graph-container {
+ width: 800px;
+}
+
+#control {
+ width: 320px;
+ height: 800px;
+}
+
+#list {
+ width: 300px;
+ height: 300px;
+ margin: 10px;
+}
+
+#details {
+ width: 300px;
+ height: 440px;
+ margin: 10px;
+}
+
+#title {
+ text-align: center;
+ font-size: 12px;
+}
+
+#leaderboard_table {
+ width: 95%;
+ margin: 10px;
+}
+
+#details_table {
+ width: 95%;
+ margin: 10px;
+}
+
+.bordered {
+ border: 2px solid grey;
+}
+
+#leaderboard_div {
+ height: 240px;
+}
+
+#details_div {
+ height: 380px;
+}
+
+.scrollit {
+ overflow-x: hidden;
+ overflow-y: auto;
+}
+
+tr:nth-child(even) {
+ background-color: #D6EEEE;
+}
+
+table, th, td {
+ border: 1px solid black;
+}
diff --git a/src/components/DevLeaderboard/index.js b/src/components/DevLeaderboard/index.js
new file mode 100644
index 0000000..f918330
--- /dev/null
+++ b/src/components/DevLeaderboard/index.js
@@ -0,0 +1,67 @@
+import React, { useEffect, useState } from "react";
+import * as echarts from "echarts";
+import $ from "jquery";
+
+import Leaderboard from "./Leaderboard";
+import Details from "./Details";
+import Graph from "./Graph";
+import "./devLeaderboard.css";
+
+const DevLeaderboard = () => {
+ const [graph, setGraph] = useState(null);
+ const [selectedNodeId, setSelectedNodeId] = useState(null);
+
+ const baseUrl = "https://oss.x-lab.info/open_digger/";
+ const platform = "github"; // Replace with dynamic fetching if needed
+ const repoName = "hypertrons/hypertrons-crx"; // Replace with dynamic fetching if needed
+ const month = "202407"; // Replace with dynamic fetching if needed
+ const typeMap = new Map([
+ ["r", "repo"],
+ ["i", "issue"],
+ ["p", "pull"],
+ ["u", "user"],
+ ]);
+
+ useEffect(() => {
+ const loadData = async () => {
+ const data = await $.getJSON(
+ `${baseUrl}${platform}/${repoName}/community_openrank.json`
+ );
+ setGraph(data);
+ };
+
+ loadData();
+ }, [platform, repoName]);
+
+ const handleNodeDblClick = (id) => {
+ setSelectedNodeId(id);
+ };
+
+ return (
+
+ );
+};
+
+export default DevLeaderboard;
diff --git a/src/pages/leaderboard.mdx b/src/pages/leaderboard.mdx
index ccbcf22..f19f431 100644
--- a/src/pages/leaderboard.mdx
+++ b/src/pages/leaderboard.mdx
@@ -1,5 +1,4 @@
-这是 leaderboard 页面
-
import MetricChartComponent from '@site/src/components/OpenDiggerMetricCharts';
+import DevLeaderboard from '@site/src/components/DevLeaderboard';
-
\ No newline at end of file
+
\ No newline at end of file