People plugin : repository template support (#78)
This commit is contained in:
47
README.md
47
README.md
@@ -181,6 +181,21 @@ But there's more with [plugins](https://github.com/lowlighter/metrics/tree/maste
|
||||
<img src="https://github.com/lowlighter/lowlighter/blob/master/metrics.plugin.people.following.svg" alt="" width="400">
|
||||
</a>
|
||||
</details>
|
||||
<details><summary>Special thanks version</summary>
|
||||
<a href="#-habits">
|
||||
<img src="https://github.com/lowlighter/lowlighter/blob/master/metrics.plugin.people.thanks.svg" alt="" width="400">
|
||||
</a>
|
||||
</details>
|
||||
<details><summary>Repository template version</summary>
|
||||
<a href="#-habits">
|
||||
<img src="https://github.com/lowlighter/lowlighter/blob/master/metrics.plugin.people.repository.svg" alt="" width="400">
|
||||
</a>
|
||||
</details>
|
||||
<details><summary>Sponsorships version</summary>
|
||||
<a href="#-habits">
|
||||
<img src="https://github.com/lowlighter/lowlighter/blob/master/metrics.plugin.people.sponsorships.svg" alt="" width="400">
|
||||
</a>
|
||||
</details>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
@@ -1528,7 +1543,8 @@ Add the following to your workflow:
|
||||
|
||||
### 🧑🤝🧑 People
|
||||
|
||||
The *people* plugin displays your followers and followed users' avatars.
|
||||
The *people* plugin can display people you're following or sponsoring, and also users who're following or sponsoring you.
|
||||
In repository mode, it's possible to display sponsors, stargazers, watchers.
|
||||
|
||||

|
||||
|
||||
@@ -1537,6 +1553,24 @@ The *people* plugin displays your followers and followed users' avatars.
|
||||
|
||||
It will consume an additional GitHub request per group of 100 users fetched.
|
||||
|
||||
The following types are supported:
|
||||
|
||||
| Type | Alias | User metrics | Repository metrics |
|
||||
| --------------- | ------------------------------------ | :----------------: | :----------------: |
|
||||
| `followers` | | ✔️ | ❌ |
|
||||
| `following` | `followed` | ✔️ | ❌ |
|
||||
| `sponsoring`* | `sponsored`, `sponsorshipsAsSponsor` | ✔️ | ❌ |
|
||||
| `sponsors`* | `sponsorshipsAsMaintainer` | ✔️ | ✔️ |
|
||||
| `contributors`* | | ❌ | ✔️ |
|
||||
| `stargazers`* | | ❌ | ✔️ |
|
||||
| `watchers`* | | ❌ | ✔️ |
|
||||
| `thanks`* | | ✔️ | ✔️ |
|
||||
|
||||
🚧 Types marked with * are available as pre-release on @master branch (unstable)
|
||||
|
||||
Sections will be ordered the same as specified in `plugin_people_types`.
|
||||
`sponsors` for repositories will output the same as the owner's sponsors.
|
||||
|
||||
Add the following to your workflow:
|
||||
```yaml
|
||||
- uses: lowlighter/metrics@latest
|
||||
@@ -1557,6 +1591,17 @@ It is possible to use [identicons](https://github.blog/2013-08-14-identicons/) i
|
||||
plugin_people_identicons: yes
|
||||
```
|
||||
|
||||
🚧 This feature is available as pre-release on @master branch (unstable)
|
||||
|
||||
It is possible to thanks personally users by adding the following to your workflow:
|
||||
```yaml
|
||||
- uses: lowlighter/metrics@master
|
||||
with:
|
||||
# ... other options
|
||||
plugin_people_types: thanks
|
||||
plugin_people_thanks: github-user-1, github-user-2, ...
|
||||
```
|
||||
|
||||
</details>
|
||||
|
||||
### 🌸 Anilist
|
||||
|
||||
20
action.yml
20
action.yml
@@ -469,13 +469,29 @@ inputs:
|
||||
default: 28
|
||||
|
||||
# List of users categories to display (comma separated)
|
||||
# Supported values are:
|
||||
# For user's metrics, supported values are:
|
||||
# - "followers"
|
||||
# - "following"
|
||||
# - "following"/"followed"
|
||||
# - "sponsors"/"sponsorshipsAsMaintainer"
|
||||
# - "sponsoring"/"sponsored"/"sponsorshipsAsSponsor"
|
||||
# - "thanks" (see "plugin_people_thanks" below)
|
||||
# For repositories' metrics, supported values are:
|
||||
# - "contributors"
|
||||
# - "stargazers"
|
||||
# - "watchers"
|
||||
# - "sponsors"/"sponsorshipsAsMaintainer"
|
||||
# - "thanks" (see "plugin_people_thanks" below)
|
||||
plugin_people_types:
|
||||
description: Categories to display
|
||||
default: followers, following
|
||||
|
||||
# List of users to thanks (comma seperated)
|
||||
# When using "thanks" as a type, it'll display the users you listed in this option
|
||||
# This can be used to create "Special thanks" badges that you can embed elsewhere
|
||||
plugin_people_thanks:
|
||||
description: Users to thanks in "thanks" section type
|
||||
default: ""
|
||||
|
||||
# Display GitHub identicons instead of users' real avatar
|
||||
# Mostly for privacy purposes
|
||||
plugin_people_identicons:
|
||||
|
||||
@@ -239,7 +239,7 @@
|
||||
if (plugins.people.enabled) {
|
||||
for (const option of ["limit", "size"])
|
||||
info(`People ${option}`, q[`people.${option}`] = input.number(`plugin_people_${option}`))
|
||||
for (const option of ["types"])
|
||||
for (const option of ["types", "thanks"])
|
||||
info(`People ${option}`, q[`people.${option}`] = input.array(`plugin_people_${option}`))
|
||||
for (const option of ["identicons"])
|
||||
info(`People ${option}`, q[`people.${option}`] = input.bool(`plugin_people_${option}`))
|
||||
|
||||
@@ -362,7 +362,7 @@
|
||||
}) : ({
|
||||
user:{
|
||||
[type]:{
|
||||
edges:new Array(Math.ceil(20+80*Math.random())).fill(undefined).map((login = faker.internet.userName()) => ({
|
||||
edges:new Array(Math.ceil(20+80*Math.random())).fill(null).map((login = faker.internet.userName()) => ({
|
||||
cursor:"MOCKED_CURSOR",
|
||||
node:{
|
||||
login,
|
||||
@@ -373,6 +373,66 @@
|
||||
}
|
||||
})
|
||||
}
|
||||
//People query (repositories)
|
||||
if (/^query PeopleRepository /.test(query)) {
|
||||
console.debug(`metrics/compute/mocks > mocking graphql api result > People`)
|
||||
const type = query.match(/(?<type>stargazers|watchers)[(]/)?.groups?.type ?? "(unknown type)"
|
||||
return /after: "MOCKED_CURSOR"/m.test(query) ? ({
|
||||
user:{
|
||||
repository:{
|
||||
[type]:{
|
||||
edges:[],
|
||||
}
|
||||
}
|
||||
}
|
||||
}) : ({
|
||||
user:{
|
||||
repository:{
|
||||
[type]:{
|
||||
edges:new Array(Math.ceil(20+80*Math.random())).fill(null).map((login = faker.internet.userName()) => ({
|
||||
cursor:"MOCKED_CURSOR",
|
||||
node:{
|
||||
login,
|
||||
avatarUrl:null,
|
||||
}
|
||||
}))
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
//People sponsors query
|
||||
if (/^query PeopleSponsors /.test(query)) {
|
||||
console.debug(`metrics/compute/mocks > mocking graphql api result > People`)
|
||||
const type = query.match(/(?<type>sponsorshipsAsSponsor|sponsorshipsAsMaintainer)[(]/)?.groups?.type ?? "(unknown type)"
|
||||
return /after: "MOCKED_CURSOR"/m.test(query) ? ({
|
||||
user:{
|
||||
login,
|
||||
[type]:{
|
||||
edges:[]
|
||||
}
|
||||
}
|
||||
}) : ({
|
||||
user:{
|
||||
login,
|
||||
[type]:{
|
||||
edges:new Array(Math.ceil(20+80*Math.random())).fill(null).map((login = faker.internet.userName()) => ({
|
||||
cursor:"MOCKED_CURSOR",
|
||||
node:{
|
||||
sponsorEntity:{
|
||||
login:faker.internet.userName(),
|
||||
avatarUrl:null,
|
||||
},
|
||||
sponsorable:{
|
||||
login:faker.internet.userName(),
|
||||
avatarUrl:null,
|
||||
}
|
||||
}
|
||||
}))
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
//Unmocked call
|
||||
return target(...args)
|
||||
}
|
||||
@@ -389,6 +449,8 @@
|
||||
getViews:rest.repos.getViews,
|
||||
getContributorsStats:rest.repos.getContributorsStats,
|
||||
listCommits:rest.repos.listCommits,
|
||||
listContributors:rest.repos.listContributors,
|
||||
getByUsername:rest.users.getByUsername,
|
||||
}
|
||||
|
||||
//Raw request
|
||||
@@ -893,6 +955,49 @@
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
//Repository contributors
|
||||
rest.repos.listContributors = new Proxy(unmocked.listContributors, {
|
||||
apply:function(target, that, [{owner, repo}]) {
|
||||
console.debug(`metrics/compute/mocks > mocking rest api result > rest.repos.listContributors`)
|
||||
return ({
|
||||
status:200,
|
||||
url:`https://api.github.com/repos/${owner}/${repo}/contributors`,
|
||||
headers: {
|
||||
server:"GitHub.com",
|
||||
status:"200 OK",
|
||||
"x-oauth-scopes":"repo",
|
||||
},
|
||||
data:new Array(40+faker.random.number(60)).fill(null).map(() => ({
|
||||
login:faker.internet.userName(),
|
||||
avatar_url:null,
|
||||
contributions:faker.random.number(1000),
|
||||
}))
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
//User informations
|
||||
rest.users.getByUsername = new Proxy(unmocked.getByUsername, {
|
||||
apply:function(target, that, [{username}]) {
|
||||
console.debug(`metrics/compute/mocks > mocking rest api result > rest.repos.getByUsername`)
|
||||
return ({
|
||||
status:200,
|
||||
url:`'https://api.github.com/users/${username}/`,
|
||||
headers: {
|
||||
server:"GitHub.com",
|
||||
status:"200 OK",
|
||||
"x-oauth-scopes":"repo",
|
||||
},
|
||||
data:{
|
||||
login:faker.internet.userName(),
|
||||
avatar_url:null,
|
||||
contributions:faker.random.number(1000),
|
||||
}
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
}
|
||||
|
||||
//Axios mocking
|
||||
|
||||
@@ -76,7 +76,7 @@
|
||||
stars:"🌟 Recently starred repositories",
|
||||
stargazers:"✨ Stargazers over last weeks",
|
||||
activity:"📰 Recent activity",
|
||||
people:"🧑🤝🧑 Followers and followed",
|
||||
people:"🧑🤝🧑 People",
|
||||
anilist:"🌸 Anilist",
|
||||
base:"🗃️ Base content",
|
||||
"base.header":"Header",
|
||||
@@ -120,6 +120,7 @@
|
||||
"people.size":{text:"Limit", type:"number", min:16, max:64},
|
||||
"people.limit":{text:"Limit", type:"number", min:1, max:9999},
|
||||
"people.types":{text:"Types", placeholder:"followers, following"},
|
||||
"people.thanks":{text:"Special thanks", placeholder:"user1, user2, ..."},
|
||||
"people.identicons":{text:"Use identicons", type:"boolean"},
|
||||
"anilist.medias":{text:"Medias to display", placeholder:"anime, manga"},
|
||||
"anilist.sections":{text:"Sections to display", placeholder:"favorites, watching, reading, characters"},
|
||||
@@ -157,6 +158,7 @@
|
||||
"people.size":28,
|
||||
"people.limit":28,
|
||||
"people.types":"followers, following",
|
||||
"people.thanks":"",
|
||||
"people.identicons":false,
|
||||
"anilist.medias":"anime, manga",
|
||||
"anilist.sections":"favorites",
|
||||
|
||||
@@ -222,17 +222,25 @@
|
||||
}) : null),
|
||||
//People
|
||||
...(set.plugins.enabled.people ? ({
|
||||
people:{
|
||||
types:options["people.types"].split(",").map(x => x.trim()),
|
||||
size:options["people.size"],
|
||||
followers:new Array(Number(options["people.limit"])).fill(null).map(_ => ({
|
||||
login:faker.internet.userName(),
|
||||
avatar:"iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mOcOnfpfwAGfgLYttYINwAAAABJRU5ErkJggg==",
|
||||
})),
|
||||
following:new Array(Number(options["people.limit"])).fill(null).map(_ => ({
|
||||
login:faker.internet.userName(),
|
||||
avatar:"iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mOcOnfpfwAGfgLYttYINwAAAABJRU5ErkJggg==",
|
||||
}))
|
||||
get people() {
|
||||
const types = options["people.types"].split(",").map(x => x.trim())
|
||||
.map(x => ({followed:"following", sponsors:"sponsorshipsAsMaintainer", sponsored:"sponsorshipsAsSponsor", sponsoring:"sponsorshipsAsSponsor"})[x] ?? x)
|
||||
.filter(x => ["followers", "following", "sponsorshipsAsMaintainer", "sponsorshipsAsSponsor"].includes(x))
|
||||
return {
|
||||
types,
|
||||
size:options["people.size"],
|
||||
...(Object.fromEntries(types.map(type => [
|
||||
type,
|
||||
new Array(Number(options["people.limit"])).fill(null).map(_ => ({
|
||||
login:faker.internet.userName(),
|
||||
avatar:"iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mOcOnfpfwAGfgLYttYINwAAAABJRU5ErkJggg==",
|
||||
}))
|
||||
]))),
|
||||
thanks:options["people.thanks"].split(",").map(x => x.trim()).map(login => ({
|
||||
login,
|
||||
avatar:"iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mOcOnfpfwAGfgLYttYINwAAAABJRU5ErkJggg==",
|
||||
}))
|
||||
}
|
||||
}
|
||||
}) : null),
|
||||
//Music
|
||||
|
||||
@@ -1,33 +1,66 @@
|
||||
//Setup
|
||||
export default async function ({login, graphql, q, queries, imports}, {enabled = false} = {}) {
|
||||
export default async function ({login, data, graphql, rest, q, queries, imports}, {enabled = false} = {}) {
|
||||
//Plugin execution
|
||||
try {
|
||||
//Check if plugin is enabled and requirements are met
|
||||
if ((!enabled)||(!q.people))
|
||||
return null
|
||||
|
||||
//Context
|
||||
let context = {
|
||||
mode:"user",
|
||||
types:["followers", "following", "sponsorshipsAsMaintainer", "sponsorshipsAsSponsor", "thanks"],
|
||||
default:"followers, following",
|
||||
alias:{followed:"following", sponsors:"sponsorshipsAsMaintainer", sponsored:"sponsorshipsAsSponsor", sponsoring:"sponsorshipsAsSponsor"},
|
||||
sponsorships:{sponsorshipsAsMaintainer:"sponsorEntity", sponsorshipsAsSponsor:"sponsorable"}
|
||||
}
|
||||
if (q.repo) {
|
||||
console.debug(`metrics/compute/${login}/plugins > people > switched to repository mode`)
|
||||
const {owner, repo} = data.user.repositories.nodes.map(({name:repo, owner:{login:owner}}) => ({repo, owner})).shift()
|
||||
context = {...context, mode:"repo", types:["contributors", "stargazers", "watchers", "sponsorshipsAsMaintainer", "thanks"], default:"stargazers, watchers", owner, repo}
|
||||
}
|
||||
|
||||
//Parameters override
|
||||
let {"people.limit":limit = 28, "people.types":types = "followers, following", "people.size":size = 28, "people.identicons":identicons = false} = q
|
||||
let {"people.limit":limit = 28, "people.types":types = context.default, "people.size":size = 28, "people.identicons":identicons = false, "people.thanks":thanks = []} = q
|
||||
//Limit
|
||||
limit = Math.max(1, limit)
|
||||
//Repositories projects
|
||||
types = decodeURIComponent(types ?? "").split(",").map(type => type.trim()).filter(type => ["followers", "following"].includes(type)) ?? []
|
||||
types = [...new Set(decodeURIComponent(types ?? "").split(",").map(type => type.trim()).map(type => (context.alias[type] ?? type)).filter(type => context.types.includes(type)) ?? [])]
|
||||
//Special thanks
|
||||
thanks = decodeURIComponent(thanks ?? "").split(",").map(user => user.trim()).filter(user => user)
|
||||
|
||||
//Retrieve followers from graphql api
|
||||
console.debug(`metrics/compute/${login}/plugins > people > querying api`)
|
||||
const result = {followers:[], following:[]}
|
||||
const result = Object.fromEntries(types.map(type => [type, []]))
|
||||
for (const type of types) {
|
||||
//Iterate through people
|
||||
console.debug(`metrics/compute/${login}/plugins > people > retrieving ${type}`)
|
||||
let cursor = null
|
||||
let pushed = 0
|
||||
do {
|
||||
console.debug(`metrics/compute/${login}/plugins > people > retrieving ${type} after ${cursor}`)
|
||||
const {user:{[type]:{edges}}} = await graphql(queries.people({login, type, size, after:cursor ? `after: "${cursor}"` : ""}))
|
||||
cursor = edges?.[edges?.length-1]?.cursor
|
||||
result[type].push(...edges.map(({node}) => node))
|
||||
pushed = edges.length
|
||||
} while ((pushed)&&(cursor))
|
||||
//Rest
|
||||
if (type === "contributors") {
|
||||
const {owner, repo} = context
|
||||
const {data:nodes} = await rest.repos.listContributors({owner, repo})
|
||||
result[type].push(...nodes.map(({login, avatar_url}) => ({login, avatarUrl:avatar_url})))
|
||||
}
|
||||
else if (type === "thanks") {
|
||||
const nodes = await Promise.all(thanks.map(async username => (await rest.users.getByUsername({username})).data))
|
||||
result[type].push(...nodes.map(({login, avatar_url}) => ({login, avatarUrl:avatar_url})))
|
||||
}
|
||||
//GraphQL
|
||||
else {
|
||||
let cursor = null
|
||||
let pushed = 0
|
||||
do {
|
||||
console.debug(`metrics/compute/${login}/plugins > people > retrieving ${type} after ${cursor}`)
|
||||
const {[type]:{edges}} = (
|
||||
type in context.sponsorships ? (await graphql(queries["people.sponsors"]({login:context.owner ?? login, type, size, after:cursor ? `after: "${cursor}"` : "", target:context.sponsorships[type]}))).user :
|
||||
context.mode === "repo" ? (await graphql(queries["people.repository"]({login:context.owner, repository:context.repo, type, size, after:cursor ? `after: "${cursor}"` : ""}))).user.repository :
|
||||
(await graphql(queries.people({login, type, size, after:cursor ? `after: "${cursor}"` : ""}))).user
|
||||
)
|
||||
cursor = edges?.[edges?.length-1]?.cursor
|
||||
result[type].push(...edges.map(({node}) => node[context.sponsorships[type]] ?? node))
|
||||
pushed = edges.length
|
||||
} while ((pushed)&&(cursor)&&(result[type].length <= limit))
|
||||
}
|
||||
//Limit people
|
||||
if (limit > 0) {
|
||||
console.debug(`metrics/compute/${login}/plugins > people > keeping only ${limit} ${type}`)
|
||||
|
||||
@@ -1,14 +1,13 @@
|
||||
query Repository {
|
||||
query PeopleRepository {
|
||||
user(login: "$login") {
|
||||
repository(name: "$repository") {
|
||||
$type(first: 100) {
|
||||
pageInfo {
|
||||
hasNextPage
|
||||
endCursor
|
||||
}
|
||||
nodes {
|
||||
avatarUrl(size: 24)
|
||||
login
|
||||
$type($after first: 100) {
|
||||
edges {
|
||||
cursor
|
||||
node {
|
||||
login
|
||||
avatarUrl(size: $size)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
18
source/queries/people.sponsors.graphql
Normal file
18
source/queries/people.sponsors.graphql
Normal file
@@ -0,0 +1,18 @@
|
||||
query PeopleSponsors {
|
||||
user(login: "$login") {
|
||||
login
|
||||
$type($after first: 100) {
|
||||
edges {
|
||||
cursor
|
||||
node {
|
||||
$target {
|
||||
... on User {
|
||||
login
|
||||
avatarUrl(size: $size)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -15,11 +15,15 @@
|
||||
</div>
|
||||
</section>
|
||||
<% } else { %>
|
||||
<% if (plugins.people.types?.includes("followers")) { %>
|
||||
<% for (const type of plugins.people.types) { %>
|
||||
<section>
|
||||
<h2 class="field">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" width="16" height="16"><path fill-rule="evenodd" d="M5.5 3.5a2 2 0 100 4 2 2 0 000-4zM2 5.5a3.5 3.5 0 115.898 2.549 5.507 5.507 0 013.034 4.084.75.75 0 11-1.482.235 4.001 4.001 0 00-7.9 0 .75.75 0 01-1.482-.236A5.507 5.507 0 013.102 8.05 3.49 3.49 0 012 5.5zM11 4a.75.75 0 100 1.5 1.5 1.5 0 01.666 2.844.75.75 0 00-.416.672v.352a.75.75 0 00.574.73c1.2.289 2.162 1.2 2.522 2.372a.75.75 0 101.434-.44 5.01 5.01 0 00-2.56-3.012A3 3 0 0011 4z"></path></svg>
|
||||
<%= user.followers.totalCount %> follower<%= s(user.followers.totalCount) %>
|
||||
<% if (type === "thanks") { %>
|
||||
Special thanks
|
||||
<% } else { %>
|
||||
<%= user[type].totalCount %> <%= {followers:`follower${s(user[type].totalCount)}`, following:"followed", sponsorshipsAsSponsor:"sponsored", sponsorshipsAsMaintainer:`sponsor${s(user[type].totalCount)}`}[type] %>
|
||||
<% } %>
|
||||
</h2>
|
||||
<div class="row">
|
||||
<section class="people">
|
||||
@@ -29,27 +33,7 @@
|
||||
<%= plugins.people.error.message %>
|
||||
</div>
|
||||
<% } else { %>
|
||||
<% for (const user of plugins.people.followers) { %><img class="avatar" src="data:image/png;base64,<%= user.avatar %>" width="<%= plugins.people.size %>" height="<%= plugins.people.size %>" alt="" /><% } %>
|
||||
<% } %>
|
||||
</section>
|
||||
</div>
|
||||
</section>
|
||||
<% } %>
|
||||
<% if (plugins.people.types?.includes("following")) { %>
|
||||
<section>
|
||||
<h2 class="field">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" width="16" height="16"><path fill-rule="evenodd" d="M5.5 3.5a2 2 0 100 4 2 2 0 000-4zM2 5.5a3.5 3.5 0 115.898 2.549 5.507 5.507 0 013.034 4.084.75.75 0 11-1.482.235 4.001 4.001 0 00-7.9 0 .75.75 0 01-1.482-.236A5.507 5.507 0 013.102 8.05 3.49 3.49 0 012 5.5zM11 4a.75.75 0 100 1.5 1.5 1.5 0 01.666 2.844.75.75 0 00-.416.672v.352a.75.75 0 00.574.73c1.2.289 2.162 1.2 2.522 2.372a.75.75 0 101.434-.44 5.01 5.01 0 00-2.56-3.012A3 3 0 0011 4z"></path></svg>
|
||||
<%= user.following.totalCount %> followed
|
||||
</h2>
|
||||
<div class="row">
|
||||
<section class="people">
|
||||
<% if (plugins.people.error) { %>
|
||||
<div class="field error">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" width="16" height="16"><path fill-rule="evenodd" d="M2.343 13.657A8 8 0 1113.657 2.343 8 8 0 012.343 13.657zM6.03 4.97a.75.75 0 00-1.06 1.06L6.94 8 4.97 9.97a.75.75 0 101.06 1.06L8 9.06l1.97 1.97a.75.75 0 101.06-1.06L9.06 8l1.97-1.97a.75.75 0 10-1.06-1.06L8 6.94 6.03 4.97z"></path></svg>
|
||||
<%= plugins.people.error.message %>
|
||||
</div>
|
||||
<% } else { %>
|
||||
<% for (const user of plugins.people.following) { %><img class="avatar" src="data:image/png;base64,<%= user.avatar %>" width="<%= plugins.people.size %>" height="<%= plugins.people.size %>" alt="" /><% } %>
|
||||
<% for (const user of plugins.people[type]) { %><img class="avatar" src="data:image/png;base64,<%= user.avatar %>" width="<%= plugins.people.size %>" height="<%= plugins.people.size %>" alt="" /><% } %>
|
||||
<% } %>
|
||||
</section>
|
||||
</div>
|
||||
|
||||
@@ -4,5 +4,6 @@
|
||||
"languages",
|
||||
"projects",
|
||||
"pagespeed",
|
||||
"stargazers"
|
||||
"stargazers",
|
||||
"people"
|
||||
]
|
||||
43
source/templates/repository/partials/people.ejs
Normal file
43
source/templates/repository/partials/people.ejs
Normal file
@@ -0,0 +1,43 @@
|
||||
<% if (plugins.people) { %>
|
||||
<% if (plugins.people.error) { %>
|
||||
<section>
|
||||
<h2 class="field">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" width="16" height="16"><path fill-rule="evenodd" d="M5.5 3.5a2 2 0 100 4 2 2 0 000-4zM2 5.5a3.5 3.5 0 115.898 2.549 5.507 5.507 0 013.034 4.084.75.75 0 11-1.482.235 4.001 4.001 0 00-7.9 0 .75.75 0 01-1.482-.236A5.507 5.507 0 013.102 8.05 3.49 3.49 0 012 5.5zM11 4a.75.75 0 100 1.5 1.5 1.5 0 01.666 2.844.75.75 0 00-.416.672v.352a.75.75 0 00.574.73c1.2.289 2.162 1.2 2.522 2.372a.75.75 0 101.434-.44 5.01 5.01 0 00-2.56-3.012A3 3 0 0011 4z"></path></svg>
|
||||
People
|
||||
</h2>
|
||||
<div class="row">
|
||||
<section>
|
||||
<div class="field error">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" width="16" height="16"><path fill-rule="evenodd" d="M2.343 13.657A8 8 0 1113.657 2.343 8 8 0 012.343 13.657zM6.03 4.97a.75.75 0 00-1.06 1.06L6.94 8 4.97 9.97a.75.75 0 101.06 1.06L8 9.06l1.97 1.97a.75.75 0 101.06-1.06L9.06 8l1.97-1.97a.75.75 0 10-1.06-1.06L8 6.94 6.03 4.97z"></path></svg>
|
||||
<%= plugins.people.error.message %>
|
||||
</div>
|
||||
</section>
|
||||
</div>
|
||||
</section>
|
||||
<% } else { %>
|
||||
<% for (const type of plugins.people.types) { %>
|
||||
<section>
|
||||
<h2 class="field">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" width="16" height="16"><path fill-rule="evenodd" d="M5.5 3.5a2 2 0 100 4 2 2 0 000-4zM2 5.5a3.5 3.5 0 115.898 2.549 5.507 5.507 0 013.034 4.084.75.75 0 11-1.482.235 4.001 4.001 0 00-7.9 0 .75.75 0 01-1.482-.236A5.507 5.507 0 013.102 8.05 3.49 3.49 0 012 5.5zM11 4a.75.75 0 100 1.5 1.5 1.5 0 01.666 2.844.75.75 0 00-.416.672v.352a.75.75 0 00.574.73c1.2.289 2.162 1.2 2.522 2.372a.75.75 0 101.434-.44 5.01 5.01 0 00-2.56-3.012A3 3 0 0011 4z"></path></svg>
|
||||
<% if (type === "thanks") { %>
|
||||
Special thanks
|
||||
<% } else { %>
|
||||
<%= repo[type].totalCount %> <%= {watchers:`watcher${s(repo[type].totalCount)}`, stargazers:`stargazer${s(repo[type].totalCount)}`, contributors:`contributor${s(repo[type].totalCount)}`, sponsorshipsAsSponsor:"sponsored", sponsorshipsAsMaintainer:`sponsor${s(repo[type].totalCount)}`}[type] %>
|
||||
<% } %>
|
||||
</h2>
|
||||
<div class="row">
|
||||
<section class="people">
|
||||
<% if (plugins.people.error) { %>
|
||||
<div class="field error">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" width="16" height="16"><path fill-rule="evenodd" d="M2.343 13.657A8 8 0 1113.657 2.343 8 8 0 012.343 13.657zM6.03 4.97a.75.75 0 00-1.06 1.06L6.94 8 4.97 9.97a.75.75 0 101.06 1.06L8 9.06l1.97 1.97a.75.75 0 101.06-1.06L9.06 8l1.97-1.97a.75.75 0 10-1.06-1.06L8 6.94 6.03 4.97z"></path></svg>
|
||||
<%= plugins.people.error.message %>
|
||||
</div>
|
||||
<% } else { %>
|
||||
<% for (const user of plugins.people[type]) { %><img class="avatar" src="data:image/png;base64,<%= user.avatar %>" width="<%= plugins.people.size %>" height="<%= plugins.people.size %>" alt="" /><% } %>
|
||||
<% } %>
|
||||
</section>
|
||||
</div>
|
||||
</section>
|
||||
<% } %>
|
||||
<% } %>
|
||||
<% } %>
|
||||
@@ -15,6 +15,11 @@
|
||||
console.debug(`metrics/compute/${login}/${repo} > retrieving single repository ${repo}`)
|
||||
const {user:{repository}} = await graphql(queries.repository({login, repo}))
|
||||
data.user.repositories.nodes = [repository]
|
||||
data.repo = repository
|
||||
|
||||
//Contributors and sponsors
|
||||
data.repo.contributors = {totalCount:(await rest.repos.listContributors({owner:data.repo.owner.login, repo})).data.length}
|
||||
data.repo.sponsorshipsAsMaintainer = data.user.sponsorshipsAsMaintainer
|
||||
|
||||
//Get commit activity
|
||||
console.debug(`metrics/compute/${login}/${repo} > querying api for commits`)
|
||||
|
||||
@@ -286,6 +286,27 @@
|
||||
plugin_people:true,
|
||||
plugin_people_types:"following",
|
||||
}, {skip:["terminal", "repository"]}],
|
||||
["People plugin (sponsoring)", {
|
||||
plugin_people:true,
|
||||
plugin_people_types:"sponsoring",
|
||||
}, {skip:["terminal", "repository"]}],
|
||||
["People plugin (sponsors)", {
|
||||
plugin_people:true,
|
||||
plugin_people_types:"sponsors",
|
||||
}, {skip:["terminal"]}],
|
||||
["People plugin (stargazers)", {
|
||||
plugin_people:true,
|
||||
plugin_people_types:"stargazers",
|
||||
}, {skip:["classic", "terminal"]}],
|
||||
["People plugin (watchers)", {
|
||||
plugin_people:true,
|
||||
plugin_people_types:"watchers",
|
||||
}, {skip:["classic", "terminal"]}],
|
||||
["People plugin (thanks)", {
|
||||
plugin_people:true,
|
||||
plugin_people_types:"thanks",
|
||||
plugin_people_thanks:"lowlighter",
|
||||
}, {skip:["classic", "terminal"]}],
|
||||
["People plugin (identicons)", {
|
||||
plugin_people:true,
|
||||
plugin_people_identicons:true,
|
||||
|
||||
Reference in New Issue
Block a user