Skip to content

Commit

Permalink
Init dashboard
Browse files Browse the repository at this point in the history
  • Loading branch information
pearmini committed Jul 10, 2024
1 parent 64eaff7 commit 7a38b1f
Show file tree
Hide file tree
Showing 10 changed files with 3,674 additions and 0 deletions.
30 changes: 30 additions & 0 deletions .github/workflows/deploy.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
name: Deploy

on:
# Run this workflow whenever a new commit is pushed to main.
push: { branches: [master] }
# Run this workflow once per day, at 10:15 UTC
schedule: [{ cron: "00 00 * * *" }]
# Run this workflow when triggered manually in GitHub’s UI.
workflow_dispatch: {}

jobs:
deploy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: 20
cache: npm
- run: npm install
- name: Build
run: npm run build
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- name: Deploy to Observable Cloud
# This parameter to `--message` will use the latest commit message
run: npm run deploy -- --message "$(git log -1 --pretty=%s)"
env:
# Authentication information. See below for how to set this up.
OBSERVABLE_TOKEN: ${{ secrets.OBSERVABLE_TOKEN }}
26 changes: 26 additions & 0 deletions .github/workflows/preview.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
name: Preview

on:
pull_request: { branches: [master] }
# Run this workflow when triggered manually in GitHub’s UI.
workflow_dispatch: {}

jobs:
deploy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: 20
cache: npm
- run: npm install
- name: Build
run: npm run build
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- name: Deploy to GitHub Pages
uses: peaceiris/actions-gh-pages@v3
with:
github_token: ${{ secrets.GITHUB_TOKEN }}
publish_dir: ./dist
5 changes: 5 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
.DS_Store
dist/
docs/.observablehq/cache/
node_modules/
yarn-error.log
5 changes: 5 additions & 0 deletions docs/.observablehq/deploy.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
"projectId": "3a0ad35943a5d91c",
"projectSlug": "oscp",
"workspaceLogin": "antv"
}
42 changes: 42 additions & 0 deletions docs/components/bar.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
import { Chart } from "npm:@antv/g2";
import * as d3 from "npm:d3-array";

let chart;

export function bar(data, { width } = {}) {
if (chart) chart.destroy();

const groups = d3.groups(data, (d) => d.userName);

chart = new Chart({
width,
height: groups.length * 20 + 100,
marginRight: 30,
});

chart.options({
type: "interval",
title: "贡献者排行",
coordinate: { transform: [{ type: "transpose" }] },
data,
encode: {
x: "userName",
},
transform: [
{ type: "groupX", y: "count" },
{ type: "sortX", by: "y", reverse: true },
],
scale: {
x: { padding: 0.2 },
y: { nice: true },
},
axis: {
x: { title: "Github 昵称" },
y: { title: "PR 数量" },
},
});

chart.render();

return chart.getContainer();
}
81 changes: 81 additions & 0 deletions docs/data/pr.csv.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
import { csvFormat } from "d3-dsv";
import { Octokit } from "octokit";

async function pr(
octokit,
{ startDate = null, repo = "G2", per_page = 100 } = {}
) {
let page = 1;
const PRs = [];
do {
const { data } = await octokit.request(`GET /repos/antvis/${repo}/pulls`, {
state: "all",
sort: "created",
direction: "desc",
page,
per_page,
headers: {
"X-GitHub-Api-Version": "2022-11-28",
},
});
if (!data.length) return PRs;
const index = data.findIndex((d, i) => {
const next = data[i + 1];
if (!next) return false;
const now = new Date(d.created_at);
const yes = new Date(next.created_at);
const start = new Date(startDate);
return now > start && start > yes;
});
const sliced = index === -1 ? data : data.slice(0, index + 1);
PRs.push(...sliced);
if (index !== -1) return PRs;
page++;
} while (startDate && page < 100);
return PRs;
}

function oneYearAgo(date) {
const year = date.getFullYear() - 1;
date.setFullYear(year);
return date.toISOString();
}

const octokit = new Octokit({
auth: process.env.GITHUB_TOKEN,
});

const startDate = oneYearAgo(new Date());

const PRs = [
...(await pr(octokit, { startDate, repo: "G2" })).map((d) => ({
...d,
repo: "G2",
})),
...(await pr(octokit, { startDate, repo: "G6" })).map((d) => ({
...d,
repo: "G6",
})),
...(await pr(octokit, { startDate, repo: "L7" })).map((d) => ({
...d,
repo: "L7",
})),
];

const ADMIN_ROLES = new Set(["MEMBER", "OWNER"]);

const data = PRs.map((d) => ({
contributor: ADMIN_ROLES.has(d.author_association) ? 0 : 1,
// author_association: d.author_association,
repo: d.repo,
userName: d.user.login,
// userAvatar: d.user.avatar_url,
mergeAt: d.merged_at,
// url: d.html_url,
// TODO: add more fields
}))
.filter((d) => d.userName !== "github-actions[bot]")
.filter((d) => d.userName !== "dependabot-preview[bot]")
.filter((d) => d.userName !== "dependabot[bot]");

process.stdout.write(csvFormat(data));
83 changes: 83 additions & 0 deletions docs/index.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
---
toc: false
---

```js
import { bar } from "./components/bar.js";
const pr = FileAttachment("data/pr.csv").csv({ typed: true });
```

```js
function monthAgo(number = 1) {
return (date) => {
const month = date.getMonth() - number;
date.setMonth(month);
return date.toISOString();
};
}

const map = new Map([
["1个月", monthAgo(1)],
["3个月", monthAgo(3)],
["半年", monthAgo(6)],
["1年", monthAgo(12)],
]);

const startDate = map.get(ago)(new Date());

const isContributor = (d) => d.contributor === 1;

const selected = pr
.filter((d) => (repo === "全部" ? true : d.repo === repo))
.filter((d) => new Date(d.mergeAt) > new Date(startDate));

const contributors = Array.from(
new Set(selected.filter(isContributor).map((d) => d.userName))
).length;

const PRs = selected.filter(isContributor).length;
const allPRs = selected.length;
const ratio = ((PRs / allPRs) * 100).toFixed(0);
```

<h1>AntV OSCP</h1>

```js
const ago = view(
Inputs.radio(["1个月", "3个月", "半年", "1年"], {
label: "时间范围",
value: "1年",
})
);
```

```js
const repo = view(
Inputs.radio(["全部", "G2", "G6", "L7"], { label: "技术栈", value: "全部" })
);
```

<div class="grid grid-cols-4">
<span class="card">
<h2>社区贡献者</h2>
<span class="big">${contributors}</span>
</span>
<span class="card">
<h2>社区贡献者 PR</h2>
<span class="big">${PRs}</span>
</span>
<span class="card">
<h2>所有 PR</h2>
<span class="big">${selected.length}</span>
</span>
<span class="card">
<h2>社区贡献率</h2>
<span class="big">${ratio + `%`}</span>
</span>
</div>

<div class="grid grid-cols-1">
<div class="card" style="padding:0">
${resize((width) => bar(selected, {width}))}
</div>
</div>
28 changes: 28 additions & 0 deletions observablehq.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
// See https://observablehq.com/framework/config for documentation.
export default {
// The project’s title; used in the sidebar and webpage titles.
title: "AntV OSCP",

// The pages and sections in the sidebar. If you don’t specify this option,
// all pages will be listed in alphabetical order. Listing pages explicitly
// lets you organize them into sections and have unlisted pages.
// pages: [
// {
// name: "Examples",
// pages: [
// {name: "Dashboard", path: "/example-dashboard"},
// {name: "Report", path: "/example-report"}
// ]
// }
// ],

// Some additional configuration options and their defaults:
// theme: "default", // try "light", "dark", "slate", etc.
// header: "", // what to show in the header (HTML)
// footer: "Built with Observable.", // what to show in the footer (HTML)
// toc: true, // whether to show the table of contents
// pager: true, // whether to show previous & next links in the footer
// root: "docs", // path to the source root for preview
// output: "dist", // path to the output root for build
// search: true, // activate search
};
Loading

0 comments on commit 7a38b1f

Please sign in to comment.