Add Stargazers plugin (#37)
This commit is contained in:
25
.github/pull_request_template.md
vendored
25
.github/pull_request_template.md
vendored
@@ -6,7 +6,30 @@
|
|||||||
-->
|
-->
|
||||||
|
|
||||||
**Pull request description**
|
**Pull request description**
|
||||||
<!-- A clear and concise description of what your pull request implements or fixs. -->
|
<!--
|
||||||
|
A clear and concise description of what your pull request implements or fixs.
|
||||||
|
|
||||||
|
Please check the following:
|
||||||
|
|
||||||
|
> Documentation update
|
||||||
|
- Check spelling
|
||||||
|
- Respect current formatting
|
||||||
|
|
||||||
|
> New plugin
|
||||||
|
- Created new plugin in /source/plugins/ with index.mjs as entry point
|
||||||
|
- Added tests in /tests/metrics.test.js
|
||||||
|
- Added mocked data if needed (required for all APIs which requires a token or limited in requests)
|
||||||
|
- Updated action.yml with new plugin options
|
||||||
|
- Updated /source/app/action/index.mjs to retrieve plugin options with correct typing
|
||||||
|
- Updated /source/web/statics/* to support new plugin options
|
||||||
|
- Updated /settings.example.json with new plugin name
|
||||||
|
- Updated README.md to explain plugin features
|
||||||
|
|
||||||
|
> Code editions
|
||||||
|
- Ensure retro-compatibility with previous versions
|
||||||
|
- Unless feature is not released yet
|
||||||
|
- Respect current formatting
|
||||||
|
-->
|
||||||
|
|
||||||
**Additional context and screenshots**
|
**Additional context and screenshots**
|
||||||
<!-- Add any other context or screenshots about your pull request here. -->
|
<!-- Add any other context or screenshots about your pull request here. -->
|
||||||
|
|||||||
41
README.md
41
README.md
@@ -147,20 +147,32 @@ But there's more with [plugins](https://github.com/lowlighter/metrics/tree/maste
|
|||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
|
<th><a href="https://github.com/lowlighter/metrics#-stargazers">✨ Stargazers evolution</a></th>
|
||||||
<th><a href="https://github.com/lowlighter/metrics#-stars">🌟 Recently starred repositories</a></th>
|
<th><a href="https://github.com/lowlighter/metrics#-stars">🌟 Recently starred repositories</a></th>
|
||||||
<th><a href="https://github.com/lowlighter/metrics#%EF%B8%8F-base-content">🗃️ Header special features</a></th>
|
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
|
<td>
|
||||||
|
<a href="https://github.com/lowlighter/metrics#-stargazers">
|
||||||
|
<img src="https://github.com/lowlighter/lowlighter/blob/master/metrics.plugin.stargazers.svg" alt="" width="400">
|
||||||
|
</a>
|
||||||
|
</td>
|
||||||
<td>
|
<td>
|
||||||
<a href="https://github.com/lowlighter/metrics#-stars">
|
<a href="https://github.com/lowlighter/metrics#-stars">
|
||||||
<img src="https://github.com/lowlighter/lowlighter/blob/master/metrics.plugin.stars.svg" alt="" width="400">
|
<img src="https://github.com/lowlighter/lowlighter/blob/master/metrics.plugin.stars.svg" alt="" width="400">
|
||||||
</a>
|
</a>
|
||||||
</td>
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<th><a href="https://github.com/lowlighter/metrics#%EF%B8%8F-base-content">🗃️ Header special features</a></th>
|
||||||
|
<th></th>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
<td>
|
<td>
|
||||||
<a href="https://github.com/lowlighter/metrics#%EF%B8%8F-base-content">
|
<a href="https://github.com/lowlighter/metrics#%EF%B8%8F-base-content">
|
||||||
<img src="https://github.com/lowlighter/lowlighter/blob/master/metrics.header.svg" alt="" width="400">
|
<img src="https://github.com/lowlighter/lowlighter/blob/master/metrics.header.svg" alt="" width="400">
|
||||||
</a>
|
</a>
|
||||||
</td>
|
</td>
|
||||||
|
<td></td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td colspan="2" align="center">
|
<td colspan="2" align="center">
|
||||||
@@ -516,6 +528,7 @@ Used template defaults to the `classic` one.
|
|||||||
<th><span title="Habits">💡</span></th>
|
<th><span title="Habits">💡</span></th>
|
||||||
<th><span title="Gists">🎫</span></th>
|
<th><span title="Gists">🎫</span></th>
|
||||||
<th><span title="Stars">🌟</span></th>
|
<th><span title="Stars">🌟</span></th>
|
||||||
|
<th><span title="Stargazers">✨</span></th>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<th>Classic</th>
|
<th>Classic</th>
|
||||||
@@ -534,6 +547,7 @@ Used template defaults to the `classic` one.
|
|||||||
<td>✔️</td>
|
<td>✔️</td>
|
||||||
<td>✔️</td>
|
<td>✔️</td>
|
||||||
<td><span title="Available on master">✔️<sup>M</sup></span></td>
|
<td><span title="Available on master">✔️<sup>M</sup></span></td>
|
||||||
|
<td><span title="Available on master">✔️<sup>M</sup></span></td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<th>Terminal</th>
|
<th>Terminal</th>
|
||||||
@@ -552,6 +566,7 @@ Used template defaults to the `classic` one.
|
|||||||
<td>❌</td>
|
<td>❌</td>
|
||||||
<td>✔️</td>
|
<td>✔️</td>
|
||||||
<td>❌</td>
|
<td>❌</td>
|
||||||
|
<td>❌</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<th>Repository<sup>R</sup></th>
|
<th>Repository<sup>R</sup></th>
|
||||||
@@ -570,6 +585,7 @@ Used template defaults to the `classic` one.
|
|||||||
<td>❌</td>
|
<td>❌</td>
|
||||||
<td>❌</td>
|
<td>❌</td>
|
||||||
<td>❌</td>
|
<td>❌</td>
|
||||||
|
<td><span title="Available on master">✔️<sup>M</sup></span></td>
|
||||||
</tr>
|
</tr>
|
||||||
</table>
|
</table>
|
||||||
|
|
||||||
@@ -1281,6 +1297,29 @@ Add the following to your workflow :
|
|||||||
|
|
||||||
</details>
|
</details>
|
||||||
|
|
||||||
|
### ✨ Stargazers
|
||||||
|
|
||||||
|
🚧 This feature is available on @master
|
||||||
|
|
||||||
|
The *stargazers* plugin displays your stargazers evolution across all of your repositories over the last two weeks.
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
<details>
|
||||||
|
<summary>💬 About</summary>
|
||||||
|
|
||||||
|
It will consume additional GitHub requests per repository per set of 100 stargazers.
|
||||||
|
|
||||||
|
Add the following to your workflow :
|
||||||
|
```yaml
|
||||||
|
- uses: lowlighter/metrics@latest
|
||||||
|
with:
|
||||||
|
# ... other options
|
||||||
|
plugin_stargazers: yes
|
||||||
|
```
|
||||||
|
|
||||||
|
</details>
|
||||||
|
|
||||||
### 🔧 Other options
|
### 🔧 Other options
|
||||||
|
|
||||||
A few additional options are available.
|
A few additional options are available.
|
||||||
|
|||||||
@@ -357,6 +357,12 @@ inputs:
|
|||||||
description: Number of recently starred repositories to display
|
description: Number of recently starred repositories to display
|
||||||
default: 4
|
default: 4
|
||||||
|
|
||||||
|
# Display stargazers evolution over the last two weeks
|
||||||
|
# It shows total stargazers along with increase rate per day
|
||||||
|
plugin_stagazers:
|
||||||
|
description: Display stargazers evolution over the last two weeks
|
||||||
|
default: no
|
||||||
|
|
||||||
# ====================================================================================
|
# ====================================================================================
|
||||||
# Options below are mostly used for testing
|
# Options below are mostly used for testing
|
||||||
|
|
||||||
|
|||||||
@@ -60,7 +60,10 @@
|
|||||||
"token":null, "//":"Twitter token (required when enabled)"
|
"token":null, "//":"Twitter token (required when enabled)"
|
||||||
},
|
},
|
||||||
"stars":{ "//":"Stars plugin",
|
"stars":{ "//":"Stars plugin",
|
||||||
"enabled":true, "//":"Enable or disable recently starred repositories display"
|
"enabled":false, "//":"Enable or disable recently starred repositories display"
|
||||||
|
},
|
||||||
|
"stargazers":{ "//":"Stargazers plugin",
|
||||||
|
"enabled":false, "//":"Enable or disable stargazers charts display"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -140,6 +140,7 @@
|
|||||||
projects:{enabled:input.bool("plugin_projects")},
|
projects:{enabled:input.bool("plugin_projects")},
|
||||||
tweets:{enabled:input.bool("plugin_tweets")},
|
tweets:{enabled:input.bool("plugin_tweets")},
|
||||||
stars:{enabled:input.bool("plugin_stars")},
|
stars:{enabled:input.bool("plugin_stars")},
|
||||||
|
stargazers:{enabled:input.bool("plugin_stargazers")},
|
||||||
}
|
}
|
||||||
let q = Object.fromEntries(Object.entries(plugins).filter(([key, plugin]) => plugin.enabled).map(([key]) => [key, true]))
|
let q = Object.fromEntries(Object.entries(plugins).filter(([key, plugin]) => plugin.enabled).map(([key]) => [key, true]))
|
||||||
info("Plugins enabled", Object.entries(plugins).filter(([key, plugin]) => plugin.enabled).map(([key]) => key))
|
info("Plugins enabled", Object.entries(plugins).filter(([key, plugin]) => plugin.enabled).map(([key]) => key))
|
||||||
|
|||||||
@@ -296,6 +296,26 @@
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
//Stargazers query
|
||||||
|
if (/^query Stargazers /.test(query)) {
|
||||||
|
console.debug(`metrics/compute/mocks > mocking graphql api result > Stargazers`)
|
||||||
|
return /after: "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"/m.test(query) ? ({
|
||||||
|
repository:{
|
||||||
|
stargazers:{
|
||||||
|
edges:[],
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}) : ({
|
||||||
|
repository:{
|
||||||
|
stargazers:{
|
||||||
|
edges:new Array(Math.ceil(20+80*Math.random())).fill(null).map(() => ({
|
||||||
|
starredAt:new Date(Date.now()-Math.floor(30*Math.random())*24*60*60*1000).toISOString(),
|
||||||
|
cursor:"xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
//Unmocked call
|
//Unmocked call
|
||||||
return target(...args)
|
return target(...args)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -47,6 +47,7 @@
|
|||||||
projects:"🗂️ Projects",
|
projects:"🗂️ Projects",
|
||||||
tweets:"🐤 Latest tweets",
|
tweets:"🐤 Latest tweets",
|
||||||
stars:"🌟 Recently starred repositories",
|
stars:"🌟 Recently starred repositories",
|
||||||
|
stargazers:"✨ Stargazers over last weeks",
|
||||||
"base.header":`
|
"base.header":`
|
||||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" width="16" height="16"><path fill-rule="evenodd" d="M0 8a8 8 0 1116 0v5.25a.75.75 0 01-1.5 0V8a6.5 6.5 0 10-13 0v5.25a.75.75 0 01-1.5 0V8zm5.5 4.25a.75.75 0 01.75-.75h3.5a.75.75 0 010 1.5h-3.5a.75.75 0 01-.75-.75zM3 6.75C3 5.784 3.784 5 4.75 5h6.5c.966 0 1.75.784 1.75 1.75v1.5A1.75 1.75 0 0111.25 10h-6.5A1.75 1.75 0 013 8.25v-1.5zm1.47-.53a.75.75 0 011.06 0l.97.97.97-.97a.75.75 0 011.06 0l.97.97.97-.97a.75.75 0 111.06 1.06l-1.5 1.5a.75.75 0 01-1.06 0L8 7.81l-.97.97a.75.75 0 01-1.06 0l-1.5-1.5a.75.75 0 010-1.06z"></path></svg>
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" width="16" height="16"><path fill-rule="evenodd" d="M0 8a8 8 0 1116 0v5.25a.75.75 0 01-1.5 0V8a6.5 6.5 0 10-13 0v5.25a.75.75 0 01-1.5 0V8zm5.5 4.25a.75.75 0 01.75-.75h3.5a.75.75 0 010 1.5h-3.5a.75.75 0 01-.75-.75zM3 6.75C3 5.784 3.784 5 4.75 5h6.5c.966 0 1.75.784 1.75 1.75v1.5A1.75 1.75 0 0111.25 10h-6.5A1.75 1.75 0 013 8.25v-1.5zm1.47-.53a.75.75 0 011.06 0l.97.97.97-.97a.75.75 0 011.06 0l.97.97.97-.97a.75.75 0 111.06 1.06l-1.5 1.5a.75.75 0 01-1.06 0L8 7.81l-.97.97a.75.75 0 01-1.06 0l-1.5-1.5a.75.75 0 010-1.06z"></path></svg>
|
||||||
Header`,
|
Header`,
|
||||||
|
|||||||
@@ -17,8 +17,10 @@
|
|||||||
|
|
||||||
<!-- Title -->
|
<!-- Title -->
|
||||||
<h1 class="title">
|
<h1 class="title">
|
||||||
|
<a href="https://github.com/lowlighter/metrics">
|
||||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" width="16" height="16"><path fill-rule="evenodd" d="M8 0C3.58 0 0 3.58 0 8c0 3.54 2.29 6.53 5.47 7.59.4.07.55-.17.55-.38 0-.19-.01-.82-.01-1.49-2.01.37-2.53-.49-2.69-.94-.09-.23-.48-.94-.82-1.13-.28-.15-.68-.52-.01-.53.63-.01 1.08.58 1.23.82.72 1.21 1.87.87 2.33.66.07-.52.28-.87.51-1.07-1.78-.2-3.64-.89-3.64-3.95 0-.87.31-1.59.82-2.15-.08-.2-.36-1.02.08-2.12 0 0 .67-.21 2.2.82.64-.18 1.32-.27 2-.27.68 0 1.36.09 2 .27 1.53-1.04 2.2-.82 2.2-.82.44 1.1.16 1.92.08 2.12.51.56.82 1.27.82 2.15 0 3.07-1.87 3.75-3.65 3.95.29.25.54.73.54 1.48 0 1.07-.01 1.93-.01 2.2 0 .21.15.46.55.38A8.013 8.013 0 0016 8c0-4.42-3.58-8-8-8z"></path></svg>
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" width="16" height="16"><path fill-rule="evenodd" d="M8 0C3.58 0 0 3.58 0 8c0 3.54 2.29 6.53 5.47 7.59.4.07.55-.17.55-.38 0-.19-.01-.82-.01-1.49-2.01.37-2.53-.49-2.69-.94-.09-.23-.48-.94-.82-1.13-.28-.15-.68-.52-.01-.53.63-.01 1.08.58 1.23.82.72 1.21 1.87.87 2.33.66.07-.52.28-.87.51-1.07-1.78-.2-3.64-.89-3.64-3.95 0-.87.31-1.59.82-2.15-.08-.2-.36-1.02.08-2.12 0 0 .67-.21 2.2.82.64-.18 1.32-.27 2-.27.68 0 1.36.09 2 .27 1.53-1.04 2.2-.82 2.2-.82.44 1.1.16 1.92.08 2.12.51.56.82 1.27.82 2.15 0 3.07-1.87 3.75-3.65 3.95.29.25.54.73.54 1.48 0 1.07-.01 1.93-.01 2.2 0 .21.15.46.55.38A8.013 8.013 0 0016 8c0-4.42-3.58-8-8-8z"></path></svg>
|
||||||
<a href="https://github.com/lowlighter/metrics">Metrics v{{ version }}</a>
|
Metrics v{{ version }}
|
||||||
|
</a>
|
||||||
</h1>
|
</h1>
|
||||||
|
|
||||||
<!-- Tabs -->
|
<!-- Tabs -->
|
||||||
@@ -29,14 +31,14 @@
|
|||||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" width="16" height="16"><path fill-rule="evenodd" d="M0 1.75A.75.75 0 01.75 1h4.253c1.227 0 2.317.59 3 1.501A3.744 3.744 0 0111.006 1h4.245a.75.75 0 01.75.75v10.5a.75.75 0 01-.75.75h-4.507a2.25 2.25 0 00-1.591.659l-.622.621a.75.75 0 01-1.06 0l-.622-.621A2.25 2.25 0 005.258 13H.75a.75.75 0 01-.75-.75V1.75zm8.755 3a2.25 2.25 0 012.25-2.25H14.5v9h-3.757c-.71 0-1.4.201-1.992.572l.004-7.322zm-1.504 7.324l.004-5.073-.002-2.253A2.25 2.25 0 005.003 2.5H1.5v9h3.757a3.75 3.75 0 011.994.574z"></path></svg>
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" width="16" height="16"><path fill-rule="evenodd" d="M0 1.75A.75.75 0 01.75 1h4.253c1.227 0 2.317.59 3 1.501A3.744 3.744 0 0111.006 1h4.245a.75.75 0 01.75.75v10.5a.75.75 0 01-.75.75h-4.507a2.25 2.25 0 00-1.591.659l-.622.621a.75.75 0 01-1.06 0l-.622-.621A2.25 2.25 0 005.258 13H.75a.75.75 0 01-.75-.75V1.75zm8.755 3a2.25 2.25 0 012.25-2.25H14.5v9h-3.757c-.71 0-1.4.201-1.992.572l.004-7.322zm-1.504 7.324l.004-5.073-.002-2.253A2.25 2.25 0 005.003 2.5H1.5v9h3.757a3.75 3.75 0 011.994.574z"></path></svg>
|
||||||
Overview
|
Overview
|
||||||
</div>
|
</div>
|
||||||
<div @click="tab = 'markdown'" class="tab" :class="{active:tab === 'markdown', disabled:!user}">
|
|
||||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" width="16" height="16"><path fill-rule="evenodd" d="M4 1.75C4 .784 4.784 0 5.75 0h5.586c.464 0 .909.184 1.237.513l2.914 2.914c.329.328.513.773.513 1.237v8.586A1.75 1.75 0 0114.25 15h-9a.75.75 0 010-1.5h9a.25.25 0 00.25-.25V6h-2.75A1.75 1.75 0 0110 4.25V1.5H5.75a.25.25 0 00-.25.25v2.5a.75.75 0 01-1.5 0v-2.5zm7.5-.188V4.25c0 .138.112.25.25.25h2.688a.252.252 0 00-.011-.013l-2.914-2.914a.272.272 0 00-.013-.011zM5.72 6.72a.75.75 0 000 1.06l1.47 1.47-1.47 1.47a.75.75 0 101.06 1.06l2-2a.75.75 0 000-1.06l-2-2a.75.75 0 00-1.06 0zM3.28 7.78a.75.75 0 00-1.06-1.06l-2 2a.75.75 0 000 1.06l2 2a.75.75 0 001.06-1.06L1.81 9.25l1.47-1.47z"></path></svg>
|
|
||||||
Markdown
|
|
||||||
</div>
|
|
||||||
<div @click="tab = 'action'" class="tab" :class="{active:tab === 'action', disabled:!user}">
|
<div @click="tab = 'action'" class="tab" :class="{active:tab === 'action', disabled:!user}">
|
||||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" width="16" height="16"><path fill-rule="evenodd" d="M1.5 8a6.5 6.5 0 1113 0 6.5 6.5 0 01-13 0zM8 0a8 8 0 100 16A8 8 0 008 0zM6.379 5.227A.25.25 0 006 5.442v5.117a.25.25 0 00.379.214l4.264-2.559a.25.25 0 000-.428L6.379 5.227z"></path></svg>
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" width="16" height="16"><path fill-rule="evenodd" d="M1.5 8a6.5 6.5 0 1113 0 6.5 6.5 0 01-13 0zM8 0a8 8 0 100 16A8 8 0 008 0zM6.379 5.227A.25.25 0 006 5.442v5.117a.25.25 0 00.379.214l4.264-2.559a.25.25 0 000-.428L6.379 5.227z"></path></svg>
|
||||||
Action
|
Action
|
||||||
</div>
|
</div>
|
||||||
|
<div @click="tab = 'markdown'" class="tab" :class="{active:tab === 'markdown', disabled:!user}">
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" width="16" height="16"><path fill-rule="evenodd" d="M4 1.75C4 .784 4.784 0 5.75 0h5.586c.464 0 .909.184 1.237.513l2.914 2.914c.329.328.513.773.513 1.237v8.586A1.75 1.75 0 0114.25 15h-9a.75.75 0 010-1.5h9a.25.25 0 00.25-.25V6h-2.75A1.75 1.75 0 0110 4.25V1.5H5.75a.25.25 0 00-.25.25v2.5a.75.75 0 01-1.5 0v-2.5zm7.5-.188V4.25c0 .138.112.25.25.25h2.688a.252.252 0 00-.011-.013l-2.914-2.914a.272.272 0 00-.013-.011zM5.72 6.72a.75.75 0 000 1.06l1.47 1.47-1.47 1.47a.75.75 0 101.06 1.06l2-2a.75.75 0 000-1.06l-2-2a.75.75 0 00-1.06 0zM3.28 7.78a.75.75 0 00-1.06-1.06l-2 2a.75.75 0 000 1.06l2 2a.75.75 0 001.06-1.06L1.81 9.25l1.47-1.47z"></path></svg>
|
||||||
|
Markdown
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</nav>
|
</nav>
|
||||||
|
|
||||||
@@ -242,7 +244,7 @@
|
|||||||
</div>
|
</div>
|
||||||
<!-- Overview -->
|
<!-- Overview -->
|
||||||
<section class="preview" v-if="tab == 'overview'">
|
<section class="preview" v-if="tab == 'overview'">
|
||||||
Once generated, click on tabs above to see the code to embed them on your real readme !
|
Once generated, click on tabs above to see the code to embed them on your real readme !<br>
|
||||||
<template v-if="generated.content">
|
<template v-if="generated.content">
|
||||||
<img class="metrics" :src="generated.content" alt="metrics">
|
<img class="metrics" :src="generated.content" alt="metrics">
|
||||||
</template>
|
</template>
|
||||||
|
|||||||
@@ -10,7 +10,6 @@
|
|||||||
background-color: var(--color-bg-canvas);
|
background-color: var(--color-bg-canvas);
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
overflow: hidden;
|
|
||||||
}
|
}
|
||||||
/* Title */
|
/* Title */
|
||||||
.title {
|
.title {
|
||||||
@@ -36,6 +35,7 @@
|
|||||||
display: flex;
|
display: flex;
|
||||||
border-bottom: 1px solid var(--color-border-secondary);
|
border-bottom: 1px solid var(--color-border-secondary);
|
||||||
flex-shrink: 0;
|
flex-shrink: 0;
|
||||||
|
overflow-x: auto;
|
||||||
}
|
}
|
||||||
nav .tab {
|
nav .tab {
|
||||||
flex-shrink: 0;
|
flex-shrink: 0;
|
||||||
@@ -287,6 +287,7 @@
|
|||||||
}
|
}
|
||||||
nav {
|
nav {
|
||||||
margin: 32px 0 24px;
|
margin: 32px 0 24px;
|
||||||
|
overflow: hidden;
|
||||||
}
|
}
|
||||||
nav .left {
|
nav .left {
|
||||||
display: block;
|
display: block;
|
||||||
@@ -297,6 +298,7 @@
|
|||||||
main {
|
main {
|
||||||
height: 100vh;
|
height: 100vh;
|
||||||
width: 100vw;
|
width: 100vw;
|
||||||
|
overflow: hidden;
|
||||||
}
|
}
|
||||||
.avatar {
|
.avatar {
|
||||||
display: flex;
|
display: flex;
|
||||||
|
|||||||
65
source/plugins/stargazers/index.mjs
Normal file
65
source/plugins/stargazers/index.mjs
Normal file
@@ -0,0 +1,65 @@
|
|||||||
|
//Setup
|
||||||
|
export default async function ({login, graphql, data, q, queries, imports}, {enabled = false} = {}) {
|
||||||
|
//Plugin execution
|
||||||
|
try {
|
||||||
|
//Check if plugin is enabled and requirements are met
|
||||||
|
if ((!enabled)||(!q.stargazers))
|
||||||
|
return null
|
||||||
|
//Retrieve stargazers from graphql api
|
||||||
|
console.debug(`metrics/compute/${login}/plugins > stargazers > querying api`)
|
||||||
|
const repositories = data.user.repositories.nodes.map(({name}) => name).slice(0, 2)
|
||||||
|
const dates = []
|
||||||
|
for (const repository of repositories) {
|
||||||
|
//Iterate through stargazers
|
||||||
|
console.debug(`metrics/compute/${login}/plugins > stargazers > retrieving stargazers of ${repository}`)
|
||||||
|
let cursor = null
|
||||||
|
let pushed = 0
|
||||||
|
do {
|
||||||
|
console.debug(`metrics/compute/${login}/plugins > stargazers > retrieving stargazers of ${repository} after ${cursor}`)
|
||||||
|
const {repository:{stargazers:{edges}}} = await graphql(queries.stargazers({login, repository, after:cursor ? `after: "${cursor}"` : ""}))
|
||||||
|
cursor = edges?.[edges?.length-1]?.cursor
|
||||||
|
console.log(edges)
|
||||||
|
dates.push(...edges.map(({starredAt}) => new Date(starredAt)))
|
||||||
|
pushed = edges.length
|
||||||
|
} while ((pushed)&&(cursor))
|
||||||
|
//Limit repositories
|
||||||
|
console.debug(`metrics/compute/${login}/plugins > stargazers > loaded ${dates.length} stargazers for ${repository}`)
|
||||||
|
}
|
||||||
|
console.debug(`metrics/compute/${login}/plugins > stargazers > loaded ${dates.length} stargazers in total`)
|
||||||
|
//Compute stargazers increments
|
||||||
|
const days = 14
|
||||||
|
const increments = {dates:Object.fromEntries([...new Array(days).fill(null).map((_, i) => [new Date(Date.now()-i*24*60*60*1000).toISOString().slice(0, 10), 0]).reverse()]), max:NaN, min:NaN}
|
||||||
|
dates
|
||||||
|
.map(date => date.toISOString().slice(0, 10))
|
||||||
|
.filter(date => date in increments.dates)
|
||||||
|
.map(date => increments.dates[date]++)
|
||||||
|
increments.min = Math.min(...Object.values(increments.dates))
|
||||||
|
increments.max = Math.max(...Object.values(increments.dates))
|
||||||
|
//Compute total stargazers
|
||||||
|
let stargazers = data.computed.repositories.stargazers
|
||||||
|
const total = {dates:{...increments.dates}, max:NaN, min:NaN}
|
||||||
|
{
|
||||||
|
const dates = Object.keys(total.dates)
|
||||||
|
for (let i = dates.length-1; i >= 0; i--) {
|
||||||
|
const date = dates[i], tomorrow = dates[i+1]
|
||||||
|
stargazers -= (increments.dates[tomorrow] ?? 0)
|
||||||
|
total.dates[date] = stargazers
|
||||||
|
}
|
||||||
|
}
|
||||||
|
total.min = Math.min(...Object.values(total.dates))
|
||||||
|
total.max = Math.max(...Object.values(total.dates))
|
||||||
|
//Format values
|
||||||
|
for (const date in increments.dates)
|
||||||
|
increments.dates[date] = `${increments.dates[date] > 0 ? "+" : ""}${imports.format(increments.dates[date])}`
|
||||||
|
for (const date in total.dates)
|
||||||
|
total.dates[date] = imports.format(total.dates[date])
|
||||||
|
//Months name
|
||||||
|
const months = ["", "Jan.", "Feb.", "Mar.", "Apr.", "May", "June", "July", "Aug.", "Sep.", "Oct.", "Nov.", "Dec."]
|
||||||
|
//Results
|
||||||
|
return {total, increments, months}
|
||||||
|
}
|
||||||
|
//Handle errors
|
||||||
|
catch (error) {
|
||||||
|
throw {error:{message:"An error occured", instance:error}}
|
||||||
|
}
|
||||||
|
}
|
||||||
10
source/queries/stargazers.graphql
Normal file
10
source/queries/stargazers.graphql
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
query Stargazers {
|
||||||
|
repository(name: "$repository", owner: "$login") {
|
||||||
|
stargazers($after first: 100, orderBy: {field: STARRED_AT, direction: ASC}) {
|
||||||
|
edges {
|
||||||
|
starredAt
|
||||||
|
cursor
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -847,6 +847,54 @@
|
|||||||
</section>
|
</section>
|
||||||
<% } %>
|
<% } %>
|
||||||
|
|
||||||
|
<% if (plugins.stargazers) { %>
|
||||||
|
<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="M8 .25a.75.75 0 01.673.418l1.882 3.815 4.21.612a.75.75 0 01.416 1.279l-3.046 2.97.719 4.192a.75.75 0 01-1.088.791L8 12.347l-3.766 1.98a.75.75 0 01-1.088-.79l.72-4.194L.818 6.374a.75.75 0 01.416-1.28l4.21-.611L7.327.668A.75.75 0 018 .25zm0 2.445L6.615 5.5a.75.75 0 01-.564.41l-3.097.45 2.24 2.184a.75.75 0 01.216.664l-.528 3.084 2.769-1.456a.75.75 0 01.698 0l2.77 1.456-.53-3.084a.75.75 0 01.216-.664l2.24-2.183-3.096-.45a.75.75 0 01-.564-.41L8 2.694v.001z"></path></svg>
|
||||||
|
Stargazers over the last two weeks
|
||||||
|
</h2>
|
||||||
|
<% if (plugins.stargazers.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.stargazers.error.message %>
|
||||||
|
</div>
|
||||||
|
<% } else { %>
|
||||||
|
<div class="row">
|
||||||
|
<section class="column chart">
|
||||||
|
<h3>Total stargazers</h3>
|
||||||
|
<div class="chart-bars">
|
||||||
|
<% { let previous = null; for (const [date, value] of Object.entries(plugins.stargazers.total.dates)) { const p = 0.05+0.95*(value-plugins.stargazers.total.min)/(plugins.stargazers.total.max-plugins.stargazers.total.min); const [y, m, d] = date.split("-").map(Number) %>
|
||||||
|
<div class="entry">
|
||||||
|
<span class="value"><%= (value-(previous ?? 0)) ? value : "" %></span>
|
||||||
|
<div class="bar" style="height: <%= p*50 %>px; background-color: var(--color-calendar-graph-day-L<%= Math.ceil(p/0.25) %>-bg)"></div>
|
||||||
|
<%= d %>
|
||||||
|
<% if ((previous === null)||(d === 1)) { %>
|
||||||
|
<div class="bottom"><%= plugins.stargazers.months[m] %></div>
|
||||||
|
<% } %>
|
||||||
|
</div>
|
||||||
|
<% previous = value } } %>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
<section class="column chart">
|
||||||
|
<h3>New stargazers per day</h3>
|
||||||
|
<div class="chart-bars">
|
||||||
|
<% { let previous = true; for (const [date, value] of Object.entries(plugins.stargazers.increments.dates)) { const p = value/plugins.stargazers.increments.max; const [y, m, d] = date.split("-").map(Number) %>
|
||||||
|
<div class="entry">
|
||||||
|
<span class="value"><%= value != 0 ? value : "" %></span>
|
||||||
|
<div class="bar" style="height: <%= p*50 %>px; background-color: var(--color-calendar-graph-day-L<%= Math.ceil(p/0.25) %>-bg)"></div>
|
||||||
|
<%= d %>
|
||||||
|
<% if ((previous === null)||(d === 1)) { %>
|
||||||
|
<div class="bottom"><%= plugins.stargazers.months[m] %></div>
|
||||||
|
<% } %>
|
||||||
|
</div>
|
||||||
|
<% previous = value } } %>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
</div>
|
||||||
|
<% } %>
|
||||||
|
</section>
|
||||||
|
<% } %>
|
||||||
|
|
||||||
<% if (base.metadata) { %>
|
<% if (base.metadata) { %>
|
||||||
<footer>
|
<footer>
|
||||||
<span>These metrics <%= !computed.token.scopes.includes("repo") ? "does not include all" : "includes" %> private contributions<% if ((config.timezone?.name)&&(!config.timezone?.error)) { %>, timezone <%= config.timezone.name %><% } %></span>
|
<span>These metrics <%= !computed.token.scopes.includes("repo") ? "does not include all" : "includes" %> private contributions<% if ((config.timezone?.name)&&(!config.timezone?.error)) { %>, timezone <%= config.timezone.name %><% } %></span>
|
||||||
|
|||||||
|
Before Width: | Height: | Size: 81 KiB After Width: | Height: | Size: 85 KiB |
@@ -79,6 +79,9 @@
|
|||||||
.fill-width {
|
.fill-width {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
}
|
}
|
||||||
|
.margin-bottom {
|
||||||
|
margin-bottom: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
/* User avatar */
|
/* User avatar */
|
||||||
.avatar {
|
.avatar {
|
||||||
@@ -367,6 +370,15 @@
|
|||||||
min-width: 30%;
|
min-width: 30%;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.chart-bars .entry {
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
|
||||||
|
.chart-bars .entry .bottom {
|
||||||
|
position: absolute;
|
||||||
|
top: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
.chart-bars.horizontal .bar {
|
.chart-bars.horizontal .bar {
|
||||||
height: 7px;
|
height: 7px;
|
||||||
width: auto;
|
width: auto;
|
||||||
|
|||||||
@@ -207,6 +207,54 @@
|
|||||||
|
|
||||||
<% } %>
|
<% } %>
|
||||||
|
|
||||||
|
<% if (plugins.stargazers) { %>
|
||||||
|
<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="M8 .25a.75.75 0 01.673.418l1.882 3.815 4.21.612a.75.75 0 01.416 1.279l-3.046 2.97.719 4.192a.75.75 0 01-1.088.791L8 12.347l-3.766 1.98a.75.75 0 01-1.088-.79l.72-4.194L.818 6.374a.75.75 0 01.416-1.28l4.21-.611L7.327.668A.75.75 0 018 .25zm0 2.445L6.615 5.5a.75.75 0 01-.564.41l-3.097.45 2.24 2.184a.75.75 0 01.216.664l-.528 3.084 2.769-1.456a.75.75 0 01.698 0l2.77 1.456-.53-3.084a.75.75 0 01.216-.664l2.24-2.183-3.096-.45a.75.75 0 01-.564-.41L8 2.694v.001z"></path></svg>
|
||||||
|
Stargazers over the last two weeks
|
||||||
|
</h2>
|
||||||
|
<% if (plugins.stargazers.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.stargazers.error.message %>
|
||||||
|
</div>
|
||||||
|
<% } else { %>
|
||||||
|
<div class="row margin-bottom">
|
||||||
|
<section class="column chart">
|
||||||
|
<h3>Total stargazers</h3>
|
||||||
|
<div class="chart-bars">
|
||||||
|
<% { let previous = null; for (const [date, value] of Object.entries(plugins.stargazers.total.dates)) { const p = 0.05+0.95*(value-plugins.stargazers.total.min)/(plugins.stargazers.total.max-plugins.stargazers.total.min); const [y, m, d] = date.split("-").map(Number) %>
|
||||||
|
<div class="entry">
|
||||||
|
<span class="value"><%= (value-(previous ?? 0)) ? value : "" %></span>
|
||||||
|
<div class="bar" style="height: <%= p*50 %>px; background-color: var(--color-calendar-graph-day-L<%= Math.ceil(p/0.25) %>-bg)"></div>
|
||||||
|
<%= d %>
|
||||||
|
<% if ((previous === null)||(d === 1)) { %>
|
||||||
|
<div class="bottom"><%= plugins.stargazers.months[m] %></div>
|
||||||
|
<% } %>
|
||||||
|
</div>
|
||||||
|
<% previous = value } } %>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
<section class="column chart">
|
||||||
|
<h3>New stargazers per day</h3>
|
||||||
|
<div class="chart-bars">
|
||||||
|
<% { let previous = true; for (const [date, value] of Object.entries(plugins.stargazers.increments.dates)) { const p = value/plugins.stargazers.increments.max; const [y, m, d] = date.split("-").map(Number) %>
|
||||||
|
<div class="entry">
|
||||||
|
<span class="value"><%= value != 0 ? value : "" %></span>
|
||||||
|
<div class="bar" style="height: <%= p*50 %>px; background-color: var(--color-calendar-graph-day-L<%= Math.ceil(p/0.25) %>-bg)"></div>
|
||||||
|
<%= d %>
|
||||||
|
<% if ((previous === null)||(d === 1)) { %>
|
||||||
|
<div class="bottom"><%= plugins.stargazers.months[m] %></div>
|
||||||
|
<% } %>
|
||||||
|
</div>
|
||||||
|
<% previous = value } } %>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
</div>
|
||||||
|
<% } %>
|
||||||
|
</section>
|
||||||
|
<% } %>
|
||||||
|
|
||||||
<% if (base.metadata) { %>
|
<% if (base.metadata) { %>
|
||||||
<footer>
|
<footer>
|
||||||
<span>Last updated <%= new Date().toGMTString() %> with lowlighter/metrics@<%= meta.version %></span>
|
<span>Last updated <%= new Date().toGMTString() %> with lowlighter/metrics@<%= meta.version %></span>
|
||||||
|
|||||||
|
Before Width: | Height: | Size: 18 KiB After Width: | Height: | Size: 22 KiB |
@@ -242,6 +242,9 @@
|
|||||||
["Stars plugin (default)", {
|
["Stars plugin (default)", {
|
||||||
plugin_stars:true,
|
plugin_stars:true,
|
||||||
}, {skip:["terminal"]}],
|
}, {skip:["terminal"]}],
|
||||||
|
["Stargazers plugin (default)", {
|
||||||
|
plugin_stargazers:true,
|
||||||
|
}, {skip:["terminal"]}],
|
||||||
]
|
]
|
||||||
|
|
||||||
//Tests run
|
//Tests run
|
||||||
|
|||||||
Reference in New Issue
Block a user