Version 2.2
- Add new template "terminal" - Add feature to flush cache of user on server - Server app improvement - Created metrics common - Package json loaded in setup
This commit is contained in:
1 parent
26bc499ef7
commit
ca0a6d559e
18 files changed
+556
-63
No files matched your search
Vendored
+1
-1
@@ -1 +1 @@
|
||||
module.exports=(()=>{var __webpack_modules__={56506:(e,t,r)=>{"use strict";r.r(t);var n={};r.r(n);r.d(n,{default:()=>E_Users_lecoq_Documents_GitHub_gitstats_src_setup});var i={};r.r(i);r.d(i,{default:()=>metrics});var o=r(35747);var a=r.n(o);var s=r(85622);var l=r.n(s);async function E_Users_lecoq_Documents_GitHub_gitstats_src_setup({log:e=true}={}){const t=e?console.debug:()=>null;t(`metrics/setup > setup`);const n="src/templates";const i={templates:{},settings:{},statics:r.ab+"html",node_modules:l().resolve("node_modules")};t(`metrics/setup > load settings.json`);if(a().existsSync(r.ab+"settings.json")){i.settings=JSON.parse(`${await a().promises.readFile(l().resolve("settings.json"))}`);t(`metrics/setup > load settings.json > success`)}else t(`metrics/setup > load settings.json > (missing)`);if(!i.settings.templates)i.settings.templates={default:"classic",enabled:[]};if(!i.settings.plugins)i.settings.plugins={};if(i.settings.debug)t(i.settings);if(a().existsSync(r.ab+"templates")){for(const e of await a().promises.readdir(n)){if(/^index.mjs$/.test(e))continue;t(`metrics/setup > load template [${e}]`);const r=[`${n}/${e}/query.graphql`,`${n}/${e}/image.svg`,`${n}/${e}/placeholder.svg`,`${n}/${e}/style.css`];const[o,s,c,u]=await Promise.all(r.map(async e=>`${await a().promises.readFile(l().resolve(e))}`));i.templates[e]={query:o,image:s,placeholder:c,style:u};t(`metrics/setup > load template [${e}] > success`);if(i.settings.debug){Object.defineProperty(i.templates,e,{get(){t(`metrics/setup > reload template [${e}]`);const[n,i,o,s]=r.map(e=>`${a().readFileSync(l().resolve(e))}`);t(`metrics/setup > reload template [${e}] > success`);return{query:n,image:i,placeholder:o,style:s}}})}}}else{t(`metrics/setup > load templates from build`);i.templates=JSON.parse(Buffer.from(`eyJjbGFzc2ljIjp7InF1ZXJ5IjoicXVlcnkgTWV0cmljcyB7XHJcbiAgdXNlcihsb2dpbjogJGxvZ2luKSB7XHJcbiAgICBuYW1lXHJcbiAgICBsb2dpblxyXG4gICAgY3JlYXRlZEF0XHJcbiAgICBhdmF0YXJVcmxcclxuICAgIHdlYnNpdGVVcmxcclxuICAgIGdpc3RzIHtcclxuICAgICAgdG90YWxDb3VudFxyXG4gICAgfVxyXG4gICAgcmVwb3NpdG9yaWVzKGxhc3Q6ICRyZXBvc2l0b3JpZXMsIGlzRm9yazogZmFsc2UsIG93bmVyQWZmaWxpYXRpb25zOiBPV05FUikge1xyXG4gICAgICB0b3RhbENvdW50XHJcbiAgICAgIG5vZGVzIHtcclxuICAgICAgICBuYW1lXHJcbiAgICAgICAgd2F0Y2hlcnMge1xyXG4gICAgICAgICAgdG90YWxDb3VudFxyXG4gICAgICAgIH1cclxuICAgICAgICBzdGFyZ2F6ZXJzIHtcclxuICAgICAgICAgIHRvdGFsQ291bnRcclxuICAgICAgICB9XHJcbiAgICAgICAgbGFuZ3VhZ2VzKGZpcnN0OiA0KSB7XHJcbiAgICAgICAgICBlZGdlcyB7XHJcbiAgICAgICAgICAgIHNpemVcclxuICAgICAgICAgICAgbm9kZSB7XHJcbiAgICAgICAgICAgICAgY29sb3JcclxuICAgICAgICAgICAgICBuYW1lXHJcbiAgICAgICAgICAgIH1cclxuICAgICAgICAgIH1cclxuICAgICAgICB9XHJcbiAgICAgICAgaXNzdWVzX29wZW46IGlzc3VlcyhzdGF0ZXM6IE9QRU4pIHtcclxuICAgICAgICAgIHRvdGFsQ291bnRcclxuICAgICAgICB9XHJcbiAgICAgICAgaXNzdWVzX2Nsb3NlZDogaXNzdWVzKHN0YXRlczogQ0xPU0VEKSB7XHJcbiAgICAgICAgICB0b3RhbENvdW50XHJcbiAgICAgICAgfVxyXG4gICAgICAgIHByX29wZW46IHB1bGxSZXF1ZXN0cyhzdGF0ZXM6IE9QRU4pIHtcclxuICAgICAgICAgIHRvdGFsQ291bnRcclxuICAgICAgICB9XHJcbiAgICAgICAgcHJfbWVyZ2VkOiBwdWxsUmVxdWVzdHMoc3RhdGVzOiBNRVJHRUQpIHtcclxuICAgICAgICAgIHRvdGFsQ291bnRcclxuICAgICAgICB9XHJcbiAgICAgICAgZm9ya0NvdW50XHJcbiAgICAgICAgbGljZW5zZUluZm8ge1xyXG4gICAgICAgICAgc3BkeElkXHJcbiAgICAgICAgfVxyXG4gICAgICB9XHJcbiAgICB9XHJcbiAgICBwYWNrYWdlcyB7XHJcbiAgICAgIHRvdGFsQ291bnRcclxuICAgIH1cclxuICAgIHN0YXJyZWRSZXBvc2l0b3JpZXMge1xyXG4gICAgICB0b3RhbENvdW50XHJcbiAgICB9XHJcbiAgICB3YXRjaGluZyB7XHJcbiAgICAgIHRvdGFsQ291bnRcclxuICAgIH1cclxuICAgIHNwb25zb3JzaGlwc0FzU3BvbnNvciB7XHJcbiAgICAgIHRvdGFsQ291bnRcclxuICAgIH1cclxuICAgIHNwb25zb3JzaGlwc0FzTWFpbnRhaW5lciB7XHJcbiAgICAgIHRvdGFsQ291bnRcclxuICAgIH1cclxuICAgIGNvbnRyaWJ1dGlvbnNDb2xsZWN0aW9uIHtcclxuICAgICAgdG90YWxSZXBvc2l0b3JpZXNXaXRoQ29udHJpYnV0ZWRDb21taXRzXHJcbiAgICAgIHRvdGFsQ29tbWl0Q29udHJpYnV0aW9uc1xyXG4gICAgICByZXN0cmljdGVkQ29udHJpYnV0aW9uc0NvdW50XHJcbiAgICAgIHRvdGFsSXNzdWVDb250cmlidXRpb25zXHJcbiAgICAgIHRvdGFsUHVsbFJlcXVlc3RDb250cmlidXRpb25zXHJcbiAgICAgIHRvdGFsUHVsbFJlcXVlc3RSZXZpZXdDb250cmlidXRpb25zXHJcbiAgICB9XHJcbiAgICBjYWxlbmRhcjpjb250cmlidXRpb25zQ29sbGVjdGlvbihmcm9tOiAkY2FsZW5kYXIuZnJvbSwgdG86ICRjYWxlbmRhci50bykge1xyXG4gICAgICBjb250cmlidXRpb25DYWxlbmRhciB7XHJcbiAgICAgICAgd2Vla3Mge1xyXG4gICAgICAgICAgY29udHJpYnV0aW9uRGF5cyB7XHJcbiAgICAgICAgICAgIGNvbG9yXHJcbiAgICAgICAgICB9XHJcbiAgICAgICAgfVxyXG4gICAgICB9XHJcbiAgICB9XHJcbiAgICByZXBvc2l0b3JpZXNDb250cmlidXRlZFRvIHtcclxuICAgICAgdG90YWxDb3VudFxyXG4gICAgfVxyXG4gICAgZm9sbG93ZXJzIHtcclxuICAgICAgdG90YWxDb3VudFxyXG4gICAgfVxyXG4gICAgZm9sbG93aW5nIHtcclxuICAgICAgdG90YWxDb3VudFxyXG4gICAgfVxyXG4gICAgaXNzdWVDb21tZW50cyB7XHJcbiAgICAgIHRvdGFsQ291bnRcclxuICAgIH1cclxuICAgIG9yZ2FuaXphdGlvbnMge1xyXG4gICAgICB0b3RhbENvdW50XHJcbiAgICB9XHJcbiAgfVxyXG59XHJcbiIsImltYWdlIjoiPHN2ZyB4bWxucz1cImh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnXCIgd2lkdGg9XCI8JT0gY29tcHV0ZWQuc3ZnLndpZHRoICU+XCIgaGVpZ2h0PVwiPCU9IGNvbXB1dGVkLnN2Zy5oZWlnaHQgJT5cIj5cclxuICA8c3R5bGU+XHJcbiAgICA8JT0gc3R5bGUgJT5cclxuICA8L3N0eWxlPlxyXG5cclxuICA8Zm9yZWlnbk9iamVjdCB4PVwiMFwiIHk9XCIwXCIgd2lkdGg9XCIxMDAlXCIgaGVpZ2h0PVwiMTAwJVwiPlxyXG4gICAgPGRp
Line truncated
|
||||
module.exports=(()=>{var __webpack_modules__={64563:(e,t,r)=>{"use strict";r.r(t);var n={};r.r(n);r.d(n,{default:()=>E_Users_lecoq_Documents_GitHub_gitstats_src_setup});var i={};r.r(i);r.d(i,{default:()=>metrics});var o=r(35747);var a=r.n(o);var s=r(85622);var l=r.n(s);async function E_Users_lecoq_Documents_GitHub_gitstats_src_setup({log:e=true}={}){const t=e?console.debug:()=>null;t(`metrics/setup > setup`);const n="src/templates";const i={templates:{},settings:{},statics:r.ab+"html",node_modules:l().resolve("node_modules")};t(`metrics/setup > load settings.json`);if(a().existsSync(r.ab+"settings.json")){i.settings=JSON.parse(`${await a().promises.readFile(l().resolve("settings.json"))}`);t(`metrics/setup > load settings.json > success`)}else t(`metrics/setup > load settings.json > (missing)`);if(!i.settings.templates)i.settings.templates={default:"classic",enabled:[]};if(!i.settings.plugins)i.settings.plugins={};if(i.settings.debug)t(i.settings);t(`metrics/setup > load package.json`);if(a().existsSync(r.ab+"package.json")){i.package=JSON.parse(`${await a().promises.readFile(l().resolve("package.json"))}`);t(`metrics/setup > load package.json > success`)}else{t(`metrics/setup > load package.json > (missing)`);i.package={version:"2.2.0"}}if(a().existsSync(r.ab+"templates")){for(const e of await a().promises.readdir(n)){if(/.*[.]mjs$/.test(e))continue;t(`metrics/setup > load template [${e}]`);const r=[`${n}/${e}/query.graphql`,`${n}/${e}/image.svg`,`${n}/${e}/placeholder.svg`,`${n}/${e}/style.css`];const[o,s,c,u]=await Promise.all(r.map(async e=>`${await a().promises.readFile(l().resolve(e))}`));i.templates[e]={query:o,image:s,placeholder:c,style:u};t(`metrics/setup > load template [${e}] > success`);if(i.settings.debug){Object.defineProperty(i.templates,e,{get(){t(`metrics/setup > reload template [${e}]`);const[n,i,o,s]=r.map(e=>`${a().readFileSync(l().resolve(e))}`);t(`metrics/setup > reload template [${e}] > success`);return{query:n,image:i,placeholder:o,style:s}}})}}}else{t(`metrics/setup > load templates from build`);i.templates=JSON.parse(Buffer.from(`eyJjbGFzc2ljIjp7InF1ZXJ5IjoicXVlcnkgTWV0cmljcyB7XHJcbiAgdXNlcihsb2dpbjogJGxvZ2luKSB7XHJcbiAgICBkYXRhYmFzZUlkXHJcbiAgICBuYW1lXHJcbiAgICBsb2dpblxyXG4gICAgY3JlYXRlZEF0XHJcbiAgICBhdmF0YXJVcmxcclxuICAgIHdlYnNpdGVVcmxcclxuICAgIGdpc3RzIHtcclxuICAgICAgdG90YWxDb3VudFxyXG4gICAgfVxyXG4gICAgcmVwb3NpdG9yaWVzKGxhc3Q6ICRyZXBvc2l0b3JpZXMsIGlzRm9yazogZmFsc2UsIG93bmVyQWZmaWxpYXRpb25zOiBPV05FUikge1xyXG4gICAgICB0b3RhbENvdW50XHJcbiAgICAgIG5vZGVzIHtcclxuICAgICAgICBuYW1lXHJcbiAgICAgICAgd2F0Y2hlcnMge1xyXG4gICAgICAgICAgdG90YWxDb3VudFxyXG4gICAgICAgIH1cclxuICAgICAgICBzdGFyZ2F6ZXJzIHtcclxuICAgICAgICAgIHRvdGFsQ291bnRcclxuICAgICAgICB9XHJcbiAgICAgICAgbGFuZ3VhZ2VzKGZpcnN0OiA0KSB7XHJcbiAgICAgICAgICBlZGdlcyB7XHJcbiAgICAgICAgICAgIHNpemVcclxuICAgICAgICAgICAgbm9kZSB7XHJcbiAgICAgICAgICAgICAgY29sb3JcclxuICAgICAgICAgICAgICBuYW1lXHJcbiAgICAgICAgICAgIH1cclxuICAgICAgICAgIH1cclxuICAgICAgICB9XHJcbiAgICAgICAgaXNzdWVzX29wZW46IGlzc3VlcyhzdGF0ZXM6IE9QRU4pIHtcclxuICAgICAgICAgIHRvdGFsQ291bnRcclxuICAgICAgICB9XHJcbiAgICAgICAgaXNzdWVzX2Nsb3NlZDogaXNzdWVzKHN0YXRlczogQ0xPU0VEKSB7XHJcbiAgICAgICAgICB0b3RhbENvdW50XHJcbiAgICAgICAgfVxyXG4gICAgICAgIHByX29wZW46IHB1bGxSZXF1ZXN0cyhzdGF0ZXM6IE9QRU4pIHtcclxuICAgICAgICAgIHRvdGFsQ291bnRcclxuICAgICAgICB9XHJcbiAgICAgICAgcHJfbWVyZ2VkOiBwdWxsUmVxdWVzdHMoc3RhdGVzOiBNRVJHRUQpIHtcclxuICAgICAgICAgIHRvdGFsQ291bnRcclxuICAgICAgICB9XHJcbiAgICAgICAgZm9ya0NvdW50XHJcbiAgICAgICAgbGljZW5zZUluZm8ge1xyXG4gICAgICAgICAgc3BkeElkXHJcbiAgICAgICAgfVxyXG4gICAgICB9XHJcbiAgICB9XHJcbiAgICBwYWNrYWdlcyB7XHJcbiAgICAgIHRvdGFsQ291bnRcclxuICAgIH1cclxuICAgIHN0YXJyZWRSZXBvc2l0b3JpZXMge1xyXG4gICAgICB0b3RhbENvdW50XHJcbiAgICB9XHJcbiAgICB3YXRjaGluZyB7XHJcbiAgICAgIHRvdGFsQ291bnRcclxuICAgIH1cclxuICAgIHNwb25zb3JzaGlwc0FzU3BvbnNvciB7XHJcbiAgICAgIHRvdGFsQ291bnRcclxuICAgIH1cclxuICAgIHNwb25zb3JzaGlwc0FzTWFpbnRhaW5lciB7XHJcbiAgICAgIHRvdGFsQ291bnRcclxuICAgIH1cclxuICAgIGNvbnRyaWJ1dGlvbnNDb2xsZWN0aW9uIHtcclxuICAgICAgdG90YWxSZXBvc2l0b3JpZXNXaXRoQ29udHJpYnV0ZWRDb21taXRzXHJcbiAgICAgIHRvdGFsQ29tbWl0Q29udHJpYnV0aW9uc1xyXG4gICAgICByZXN0cmljdGVkQ29udHJpYnV0aW9uc0NvdW50XHJcbiAgICAgIHRvdGFsSXNzdWVDb250cmlidXRpb25zXHJcbiAgICAgIHRvdGFsUHVsbFJlcXVlc3RDb250cmlidXRpb25zXHJcbiAgICAgIHRvdGFsUHVsbFJlcXVlc3RSZXZpZXdDb250cmlidXRpb25zXHJcbiAgICB9XHJcbiAgICBjYWxlbmRhcjpjb250cmlidXRpb25zQ29sbGVjdGlvbihmcm9tOiAkY2FsZW5kYXIuZnJvbSwgdG86ICRjYWxlbmRhci50bykge1xyXG4gICAgICBjb250cmlidXRpb25DYWxlbmRhciB7XHJcbiAgICAgICAgd2Vla3Mge1xyXG4gICAgICAgICAgY29udHJpYnV0aW9uRGF5cyB7XHJcbiAgICAgICAgICAgIGNvbG9yXHJcbiAgICAgICAgICB9XHJcbiAgICAgICAgfVxyXG4gICAgICB9XHJcbiAgICB9XHJcbiAgICByZXBvc2l0b3JpZXNDb250cmlidXRlZFRvIHtcclxuICAgICAgdG90YWxDb3VudFxyXG4gICAgfVxyXG4gICAgZm9sbG93ZXJzIHtcclxuICAgICAgdG90YWxDb3VudFxyXG4gICAgfVxyXG4gICAgZm9sbG93aW5nIHtcclxuICAgICAgdG90YWxDb3VudFxyXG4gICAgfVxyXG4gICAgaXNzdWVDb21tZW50cyB7XHJcbiAgICAgIHRvdGFsQ291bnRcclxuICAgIH1cclxuICAgIG9yZ2FuaXphdGlvbnMge1xyXG4gICAgICB0b3RhbENvdW50XHJcbiAgICB9XHJcbiAgfVxyXG59XHJcbiIsImltYWdlIjoiPHN2ZyB4bW
Line truncated
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "metrics",
|
||||
"version": "2.1.0",
|
||||
"version": "2.2.0",
|
||||
"description": "Generate an user's GitHub metrics as SVG image format to embed somewhere else",
|
||||
"main": "index.mjs",
|
||||
"scripts": {
|
||||
|
||||
+19
@@ -43,6 +43,7 @@
|
||||
const limiter = ratelimit({max:60, windowMs:60*1000})
|
||||
const templates = [...new Set([conf.settings.templates.default, ...(conf.settings.templates.enabled.length ? Object.keys(Templates).filter(key => conf.settings.templates.enabled.includes(key)) : Object.keys(Templates))])]
|
||||
const enabled = Object.entries(plugins).filter(([key, plugin]) => plugin.enabled).map(([key]) => key)
|
||||
const actions = {flush:new Map()}
|
||||
app.get("/", limiter, (req, res) => res.sendFile(`${conf.statics}/index.html`))
|
||||
app.get("/index.html", limiter, (req, res) => res.sendFile(`${conf.statics}/index.html`))
|
||||
app.get("/favicon.ico", limiter, (req, res) => res.sendStatus(204))
|
||||
@@ -59,6 +60,23 @@
|
||||
const {style, placeholder} = conf.templates[template]
|
||||
res.status(200).json({style, placeholder})
|
||||
})
|
||||
app.get("/action.flush", limiter, async (req, res) => {
|
||||
const {token, user} = req.query
|
||||
if (token) {
|
||||
if (actions.flush.has(token)) {
|
||||
console.debug(`metrics/app/${login} > flushed cache`)
|
||||
cache.del(actions.flush.get(token))
|
||||
return res.sendStatus(200)
|
||||
}
|
||||
else
|
||||
return res.sendStatus(404)
|
||||
}
|
||||
else {
|
||||
const token = `${Math.random().toString(16).replace("0.", "")}${Math.random().toString(16).replace("0.", "")}`
|
||||
actions.flush.set(token, user)
|
||||
return res.json({token})
|
||||
}
|
||||
})
|
||||
|
||||
//Metrics
|
||||
app.get("/:login", ...middlewares, async (req, res) => {
|
||||
@@ -84,6 +102,7 @@
|
||||
//Compute rendering
|
||||
try {
|
||||
//Render
|
||||
console.log(req.query)
|
||||
const rendered = await metrics({login, q:parse(req.query)}, {graphql, rest, plugins, conf})
|
||||
//Cache
|
||||
if ((!debug)&&(cached))
|
||||
|
||||
+8
-5
@@ -85,14 +85,15 @@
|
||||
<script src="/vue.min.js"></script>
|
||||
<script>
|
||||
;(async function() {
|
||||
const url = new URLSearchParams(window.location.search)
|
||||
new Vue({
|
||||
el:"main",
|
||||
async mounted() {
|
||||
await this.load()
|
||||
},
|
||||
data:{
|
||||
user:"",
|
||||
palette:"light",
|
||||
user:url.get("user") || "",
|
||||
palette:url.get("palette") || "light",
|
||||
plugins:{
|
||||
list:(await axios.get("/plugins.list")).data,
|
||||
enabled:{},
|
||||
@@ -109,10 +110,11 @@
|
||||
templates:{
|
||||
list:(await axios.get("/templates.list")).data,
|
||||
loaded:{},
|
||||
selected:(await axios.get("/templates.list")).data[0],
|
||||
selected:url.get("template") || (await axios.get("/templates.list")).data[0],
|
||||
placeholder:"",
|
||||
descriptions:{
|
||||
classic:"Classic template",
|
||||
terminal:"Terminal template"
|
||||
},
|
||||
},
|
||||
generated:{
|
||||
@@ -129,7 +131,7 @@
|
||||
.filter(([key, value]) => value)
|
||||
.map(([key, value]) => `${key}=${+value}`)
|
||||
.join("&")
|
||||
return `${window.location.href}${this.user}${plugins.length ? `?${plugins}` : ""}`
|
||||
return `${window.location.protocol}//${window.location.host}/${this.user}?template=${this.templates.selected}${plugins.length ? `&${plugins}` : ""}`
|
||||
},
|
||||
},
|
||||
methods:{
|
||||
@@ -144,10 +146,11 @@
|
||||
},
|
||||
async generate() {
|
||||
this.generated.pending = true
|
||||
await axios.get(`/action.flush?&token=${(await axios.get(`/action.flush?user=${this.user}`)).data.token}`)
|
||||
this.generated.content = this.serialize((await axios.get(this.url)).data)
|
||||
},
|
||||
serialize(svg) {
|
||||
return `data:image/svg+xml;base64,${btoa(svg)}`
|
||||
return `data:image/svg+xml;base64,${btoa(unescape(encodeURIComponent(svg)))}`
|
||||
},
|
||||
},
|
||||
})
|
||||
|
||||
+1
-1
@@ -34,7 +34,7 @@
|
||||
//Template
|
||||
console.debug(`metrics/compute/${login} > compute`)
|
||||
const computer = Templates[template].default || Templates[template]
|
||||
await computer({login, q}, {data, rest, graphql, plugins}, {s, pending, imports:{plugins:Plugins, imgb64}})
|
||||
await computer({login, q}, {conf, data, rest, graphql, plugins}, {s, pending, imports:{plugins:Plugins, imgb64}})
|
||||
await Promise.all(pending)
|
||||
console.debug(`metrics/compute/${login} > compute > success`)
|
||||
|
||||
|
||||
+12
-1
@@ -31,11 +31,22 @@
|
||||
if (conf.settings.debug)
|
||||
logger(conf.settings)
|
||||
|
||||
//Load package settings
|
||||
logger(`metrics/setup > load package.json`)
|
||||
if (fs.existsSync(path.resolve("package.json"))) {
|
||||
conf.package = JSON.parse(`${await fs.promises.readFile(path.resolve("package.json"))}`)
|
||||
logger(`metrics/setup > load package.json > success`)
|
||||
}
|
||||
else {
|
||||
logger(`metrics/setup > load package.json > (missing)`)
|
||||
conf.package = {version:"<#version>"}
|
||||
}
|
||||
|
||||
//Load templates
|
||||
if (fs.existsSync(path.resolve(templates))) {
|
||||
for (const name of await fs.promises.readdir(templates)) {
|
||||
//Cache templates
|
||||
if (/^index.mjs$/.test(name))
|
||||
if (/.*[.]mjs$/.test(name))
|
||||
continue
|
||||
logger(`metrics/setup > load template [${name}]`)
|
||||
const files = [
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
query Metrics {
|
||||
user(login: $login) {
|
||||
databaseId
|
||||
name
|
||||
login
|
||||
createdAt
|
||||
|
||||
@@ -45,7 +45,6 @@
|
||||
}
|
||||
.field.error svg {
|
||||
fill: #cb2431;
|
||||
|
||||
}
|
||||
|
||||
/* Displays */
|
||||
|
||||
@@ -1,52 +1,7 @@
|
||||
/** Template processort */
|
||||
export default async function ({login, q}, {data, rest, graphql, plugins}, {s, pending, imports}) {
|
||||
|
||||
//Init
|
||||
const computed = data.computed = {commits:0, sponsorships:0, licenses:{favorite:"", used:{}}, svg:{height:355, width:480}, token:{}, repositories:{watchers:0, stargazers:0, issues_open:0, issues_closed:0, pr_open:0, pr_merged:0, forks:0}, plugins:{}}
|
||||
const avatar = imports.imgb64(data.user.avatarUrl)
|
||||
|
||||
//Plugins
|
||||
if (data.user.websiteUrl)
|
||||
imports.plugins.pagespeed({login, url:data.user.websiteUrl, computed, pending, q}, plugins.pagespeed)
|
||||
imports.plugins.lines({login, repositories:data.user.repositories.nodes.map(({name}) => name), rest, computed, pending, q}, plugins.lines)
|
||||
imports.plugins.traffic({login, repositories:data.user.repositories.nodes.map(({name}) => name), rest, computed, pending, q}, plugins.traffic)
|
||||
imports.plugins.habits({login, rest, computed, pending, q}, plugins.habits)
|
||||
imports.plugins.selfskip({login, rest, computed, pending, q}, plugins.selfskip)
|
||||
imports.plugins.languages({login, data, computed, pending, q}, plugins.languages)
|
||||
imports.plugins.followup({login, data, computed, pending, q}, plugins.followup)
|
||||
|
||||
//Iterate through user's repositories
|
||||
for (const repository of data.user.repositories.nodes) {
|
||||
//Simple properties with totalCount
|
||||
for (const property of ["watchers", "stargazers", "issues_open", "issues_closed", "pr_open", "pr_merged"])
|
||||
computed.repositories[property] += repository[property].totalCount
|
||||
//Forks
|
||||
computed.repositories.forks += repository.forkCount
|
||||
//License
|
||||
if (repository.licenseInfo)
|
||||
computed.licenses.used[repository.licenseInfo.spdxId] = (computed.licenses.used[repository.licenseInfo.spdxId] || 0) + 1
|
||||
}
|
||||
|
||||
//Compute licenses stats
|
||||
computed.licenses.favorite = Object.entries(computed.licenses.used).sort(([an, a], [bn, b]) => b - a).slice(0, 1).map(([name, value]) => name) || ""
|
||||
|
||||
//Compute total commits and sponsorships
|
||||
computed.commits += data.user.contributionsCollection.totalCommitContributions + data.user.contributionsCollection.restrictedContributionsCount
|
||||
computed.sponsorships = data.user.sponsorshipsAsSponsor.totalCount + data.user.sponsorshipsAsMaintainer.totalCount
|
||||
|
||||
//Compute registration date
|
||||
const diff = (Date.now()-(new Date(data.user.createdAt)).getTime())/(365*24*60*60*1000)
|
||||
const years = Math.floor(diff)
|
||||
const months = Math.ceil((diff-years)*12)
|
||||
computed.registration = years ? `${years} year${s(years)} ago` : `${months} month${s(months)} ago`
|
||||
|
||||
//Compute calendar
|
||||
computed.calendar = data.user.calendar.contributionCalendar.weeks.flatMap(({contributionDays}) => contributionDays).slice(0, 14).reverse()
|
||||
|
||||
//Avatar (base64)
|
||||
computed.avatar = await avatar || "iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mNk+M9QDwADhgGAWjR9awAAAABJRU5ErkJggg=="
|
||||
|
||||
//Token scopes
|
||||
computed.token.scopes = (await rest.request("HEAD /")).headers["x-oauth-scopes"].split(", ")
|
||||
//Imports
|
||||
import common from "./../common.mjs"
|
||||
|
||||
/** Template processor */
|
||||
export default async function ({login, q}, {conf, data, rest, graphql, plugins}, {s, pending, imports}) {
|
||||
await common(...arguments)
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
/** Template common processor */
|
||||
export default async function ({login, q}, {conf, data, rest, graphql, plugins}, {s, pending, imports}) {
|
||||
|
||||
//Init
|
||||
const computed = data.computed = {commits:0, sponsorships:0, licenses:{favorite:"", used:{}}, svg:{height:355, width:480}, token:{}, repositories:{watchers:0, stargazers:0, issues_open:0, issues_closed:0, pr_open:0, pr_merged:0, forks:0}, plugins:{}}
|
||||
const avatar = imports.imgb64(data.user.avatarUrl)
|
||||
|
||||
//Plugins
|
||||
if (data.user.websiteUrl)
|
||||
imports.plugins.pagespeed({login, url:data.user.websiteUrl, computed, pending, q}, plugins.pagespeed)
|
||||
imports.plugins.lines({login, repositories:data.user.repositories.nodes.map(({name}) => name), rest, computed, pending, q}, plugins.lines)
|
||||
imports.plugins.traffic({login, repositories:data.user.repositories.nodes.map(({name}) => name), rest, computed, pending, q}, plugins.traffic)
|
||||
imports.plugins.habits({login, rest, computed, pending, q}, plugins.habits)
|
||||
imports.plugins.selfskip({login, rest, computed, pending, q}, plugins.selfskip)
|
||||
imports.plugins.languages({login, data, computed, pending, q}, plugins.languages)
|
||||
imports.plugins.followup({login, data, computed, pending, q}, plugins.followup)
|
||||
|
||||
//Iterate through user's repositories
|
||||
for (const repository of data.user.repositories.nodes) {
|
||||
//Simple properties with totalCount
|
||||
for (const property of ["watchers", "stargazers", "issues_open", "issues_closed", "pr_open", "pr_merged"])
|
||||
computed.repositories[property] += repository[property].totalCount
|
||||
//Forks
|
||||
computed.repositories.forks += repository.forkCount
|
||||
//License
|
||||
if (repository.licenseInfo)
|
||||
computed.licenses.used[repository.licenseInfo.spdxId] = (computed.licenses.used[repository.licenseInfo.spdxId] || 0) + 1
|
||||
}
|
||||
|
||||
//Compute licenses stats
|
||||
computed.licenses.favorite = Object.entries(computed.licenses.used).sort(([an, a], [bn, b]) => b - a).slice(0, 1).map(([name, value]) => name) || ""
|
||||
|
||||
//Compute total commits and sponsorships
|
||||
computed.commits += data.user.contributionsCollection.totalCommitContributions + data.user.contributionsCollection.restrictedContributionsCount
|
||||
computed.sponsorships = data.user.sponsorshipsAsSponsor.totalCount + data.user.sponsorshipsAsMaintainer.totalCount
|
||||
|
||||
//Compute registration date
|
||||
const diff = (Date.now()-(new Date(data.user.createdAt)).getTime())/(365*24*60*60*1000)
|
||||
const years = Math.floor(diff)
|
||||
const months = Math.ceil((diff-years)*12)
|
||||
computed.registration = years ? `${years} year${s(years)} ago` : `${months} month${s(months)} ago`
|
||||
|
||||
//Compute calendar
|
||||
computed.calendar = data.user.calendar.contributionCalendar.weeks.flatMap(({contributionDays}) => contributionDays).slice(0, 14).reverse()
|
||||
|
||||
//Avatar (base64)
|
||||
computed.avatar = await avatar || "iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mNk+M9QDwADhgGAWjR9awAAAABJRU5ErkJggg=="
|
||||
|
||||
//Token scopes
|
||||
computed.token.scopes = (await rest.request("HEAD /")).headers["x-oauth-scopes"].split(", ")
|
||||
|
||||
}
|
||||
@@ -1,7 +1,9 @@
|
||||
//Imports
|
||||
import classic from "./classic/template.mjs"
|
||||
import terminal from "./terminal/template.mjs"
|
||||
|
||||
//Exports
|
||||
export default {
|
||||
classic
|
||||
classic,
|
||||
terminal,
|
||||
}
|
||||
@@ -0,0 +1,124 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="<%= computed.svg.width %>" height="<%= computed.svg.height %>">
|
||||
<style>
|
||||
<%= style %>
|
||||
.stdin, .stdout {
|
||||
animation-duration: .2s;
|
||||
}
|
||||
.stdout {
|
||||
animation-duration: .2s;
|
||||
}
|
||||
<% for (let i = 0; i < 12; i++) { %>
|
||||
.stdin:nth-of-type(<%= i+1 %>) {
|
||||
animation-delay: <%= i*.2 %>s;
|
||||
}
|
||||
.stdout:nth-of-type(<%= i+2 %>) {
|
||||
animation-delay: <%= (i+1)*.2 %>s;
|
||||
}
|
||||
<% } %>
|
||||
footer {
|
||||
animation-delay: <%= 12*.2 %>s;
|
||||
}
|
||||
</style>
|
||||
|
||||
<foreignObject x="0" y="0" width="100%" height="100%">
|
||||
<div xmlns="http://www.w3.org/1999/xhtml" xmlns:xlink="http://www.w3.org/1999/xlink">
|
||||
|
||||
<div class="header">
|
||||
<span class="title">GitHub metrics</span>
|
||||
<div class="buttons">
|
||||
<div class="button">─</div>
|
||||
<div class="button">□</div>
|
||||
<div class="button exit">✕</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<pre><span class="banner">GitHub metrics generator <%= meta.version %>
|
||||
These generated metrics comes with ABSOLUTELY NO WARRANTY,
|
||||
to the extent permitted by applicable law.
|
||||
|
||||
Last generated: <%= new Date().toGMTString() %>
|
||||
</span>
|
||||
<div class="stdin"><%- meta.$ %> whoami</div><!--
|
||||
--><div class="stdout"><!--
|
||||
--><b><%= user.name || user.login %></b> registered=<%= computed.registration %>, uid=<%= `${user.databaseId}`.substr(-4) %>, gid=<%= user.organizations.totalCount %>, followers=<%= user.followers.totalCount %>
|
||||
contributed to <%= user.repositoriesContributedTo.totalCount %> repositor<%= s(user.repositoriesContributedTo.totalCount, "y") %> <b><% for (const [x, {color}] of Object.entries(computed.calendar)) { -%><span style="color:<%= color %>">#</span><% } %></b>
|
||||
</div>
|
||||
<div class="stdin"><%- meta.$ %> git status</div><!--
|
||||
--><div class="stdout"><b>Recent activity</b><!--
|
||||
--><b><%= `${computed.commits}`.padStart(5) %></b> commit<%= s(computed.commits) %>
|
||||
<b><%= `${user.contributionsCollection.totalPullRequestReviewContributions}`.padStart(5) %></b> pull request<%= s(user.contributionsCollection.totalPullRequestReviewContributions) %> reviewed
|
||||
<b><%= `${user.contributionsCollection.totalPullRequestContributions}`.padStart(5) %></b> pull request<%= s(user.contributionsCollection.totalPullRequestContributions) %> opened
|
||||
<b><%= `${user.contributionsCollection.totalIssueContributions}`.padStart(5) %></b> issue<%= s(user.contributionsCollection.totalIssueContributions) %> opened
|
||||
<b><%= `${user.issueComments.totalCount}`.padStart(5) %></b> issue comment<%= s(user.issueComments.totalCount) %>
|
||||
|
||||
<b>Tracked activity</b>
|
||||
<b><%= `${user.following.totalCount}`.padStart(5) %></b> user<%= s(user.followers.totalCount) %> followed
|
||||
<b><%= `${computed.sponsorships}`.padStart(5) %></b> repositor<%= s(computed.sponsorships, "y") %> sponsored
|
||||
<b><%= `${user.starredRepositories.totalCount}`.padStart(5) %></b> repositor<%= s(user.starredRepositories.totalCount, "y") %> starred
|
||||
<b><%= `${user.watching.totalCount}`.padStart(5) %></b> repositor<%= s(user.watching.totalCount, "y") %> watched
|
||||
<% if (computed.plugins.lines) { -%><% if (computed.plugins.lines.error) { -%>
|
||||
|
||||
<span class="diff error">@@ <%= computed.plugins.lines.error %> @@</span>
|
||||
<% } else { -%>
|
||||
|
||||
<span class="diff">@@ -<%= computed.plugins.lines.deleted %> +<%= computed.plugins.lines.added %> @@</span>
|
||||
<% }} -%></div>
|
||||
<div class="stdin"><%- meta.$ %> ls -lh github/repositories</div><!--
|
||||
--><div class="stdout"><!--
|
||||
-->Total <%= user.repositories.totalCount %> repositor<%= s(user.repositories.totalCount, "y") %>
|
||||
<% if (computed.plugins.traffic) { -%><% if (computed.plugins.traffic.error) { -%>
|
||||
---- <b> </b> views <span class="error">(<%= computed.plugins.traffic.error %>)</span>
|
||||
<% } else { -%>
|
||||
-r-- <b><%= `${computed.plugins.traffic.views.count}`.padStart(5) %></b> views
|
||||
<% }} -%>
|
||||
-r-- <b><%= `${computed.repositories.stargazers}`.padStart(5) %></b> stargazer<%= s(computed.repositories.stargazers) %>
|
||||
-r-- <b><%= `${computed.repositories.forks}`.padStart(5) %></b> fork<%= s(computed.repositories.forks) %>
|
||||
-r-- <b><%= `${computed.repositories.watchers}`.padStart(5) %></b> watcher<%= s(computed.repositories.watchers) %>
|
||||
dr-x <b><%= `${user.packages.totalCount}`.padStart(5) %></b> package<%= s(user.packages.totalCount) %>
|
||||
dr-x <b><%= `${user.gists.totalCount}`.padStart(5) %></b> gist<%= s(user.gists.totalCount) %>
|
||||
<% if (computed.plugins.followup) { -%><% if (computed.plugins.followup.error) { -%>
|
||||
d--- <b> </b> ISSUES <span class="error">(<%= computed.plugins.followup.error %>)</span>
|
||||
d--- <b> </b> PULL_REQUESTS <span class="error">(<%= computed.plugins.followup.error %>)</span>
|
||||
<% } else { -%>
|
||||
dr-x <b><%= `${computed.plugins.followup.issues.count}`.padStart(5) %></b> ISSUES
|
||||
-r-- <b><%= `${computed.plugins.followup.issues.open}`.padStart(5) %></b> ├── open
|
||||
-r-- <b><%= `${computed.plugins.followup.issues.closed}`.padStart(5) %></b> └── closed
|
||||
dr-x <b><%= `${computed.plugins.followup.issues.count}`.padStart(5) %></b> PULL_REQUESTS
|
||||
-r-- <b><%= `${computed.plugins.followup.pr.open}`.padStart(5) %></b> ├── open
|
||||
-r-- <b><%= `${computed.plugins.followup.pr.merged}`.padStart(5) %></b> └── merged
|
||||
<% }} -%>
|
||||
<% if (computed.licenses.favorite.length) { -%>
|
||||
dr-x LICENSE
|
||||
-r-- └── <%= computed.licenses.favorite %>
|
||||
<% } -%>
|
||||
</div><% if (computed.plugins.languages) { -%><% if (computed.plugins.languages.error) { -%>
|
||||
|
||||
<div class="stdin"><%- meta.$ %> locale</div><!--
|
||||
--><div class="stdout"><!--
|
||||
--><span class="error"><%= computed.plugins.languages.error %></span>
|
||||
<% } else { -%>
|
||||
|
||||
<div class="stdin"><%- meta.$ %> locale</div><!--
|
||||
--><div class="stdout"><!--
|
||||
--><% for (const {name, value} of computed.plugins.languages.favorites) { -%>
|
||||
<b><%= name.toLocaleUpperCase().padEnd(12) %></b> [<%= "#".repeat(Math.ceil(100*value/5)).padEnd(20) %>] <%= (100*value).toFixed(2).padEnd(5) %>%
|
||||
<% }} -%></div><% } -%><% if (computed.plugins.pagespeed) { -%><% if (computed.plugins.pagespeed.error) { -%>
|
||||
|
||||
<div class="stdin"><%- meta.$ %> curl -I <%= user.websiteUrl %></div><!--
|
||||
--><div class="stdout"><!--
|
||||
--><span class="error"><%= computed.plugins.pagespeed.error %></span>
|
||||
<% } else { -%>
|
||||
|
||||
<div class="stdin"><%- meta.$ %> curl -I <%= user.websiteUrl %></div><!--
|
||||
--><div class="stdout"><!--
|
||||
--><b>User-Agent</b>: Google PageSpeed API
|
||||
<b>Location</b>: <%= user.websiteUrl %>
|
||||
<% for (const {score, title} of computed.plugins.pagespeed.scores) { -%>
|
||||
<b><%= `X-${title.replace(/ /g, "-")}` %></b>: <%= Math.round(score*100) %>%
|
||||
<% }} -%></div><% } -%>
|
||||
|
||||
<footer>Connection reset by 127.0.0.1</footer></pre>
|
||||
</div>
|
||||
</foreignObject>
|
||||
</svg>
|
||||
|
||||
|
After Width: | Height: | Size: 6.6 KiB |
@@ -0,0 +1,88 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="480" height="<%= 640 + 80 + (!!plugins.followup)*(100+32) + (!!plugins.languages)*(170+32) + (!!plugins.lines)*(30+32) + (!!plugins.traffic)*(16+32) + (!!plugins.pagespeed)*(136+32) %>">
|
||||
<style>
|
||||
<%= style %>
|
||||
</style>
|
||||
|
||||
<foreignObject x="0" y="0" width="100%" height="100%">
|
||||
<div xmlns="http://www.w3.org/1999/xhtml" xmlns:xlink="http://www.w3.org/1999/xlink">
|
||||
|
||||
<div class="header">
|
||||
<span class="title">GitHub metrics</span>
|
||||
<div class="buttons">
|
||||
<div class="button">─</div>
|
||||
<div class="button">□</div>
|
||||
<div class="button exit">✕</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<pre><span class="banner">GitHub metrics generator X.Y.Z
|
||||
These generated metrics comes with ABSOLUTELY NO WARRANTY,
|
||||
to the extent permitted by applicable law.
|
||||
|
||||
Last generated: <%= new Date().toGMTString() %>
|
||||
</span>
|
||||
<div class="stdin"><span class="ps1-path">▇▇▇▇@metrics</span>:<span class="ps1-location">~</span># whoami</div><!--
|
||||
--><div class="stdout"><!--
|
||||
--><b>▇▇▇▇</b> registered=▇▇, uid=▇▇, gid=▇▇, followers=▇▇
|
||||
contributed to ▇▇ repositories <b style="color:#ebedf0">##############</b>
|
||||
</div>
|
||||
<div class="stdin"><span class="ps1-path">▇▇▇▇@metrics</span>:<span class="ps1-location">~</span># git status</div><!--
|
||||
--><div class="stdout"><b>Recent activity</b><!--
|
||||
--><b><%= `▇▇`.padStart(5) %></b> commits
|
||||
<b><%= `▇▇`.padStart(5) %></b> pull requests reviewed
|
||||
<b><%= `▇▇`.padStart(5) %></b> pull requests opened
|
||||
<b><%= `▇▇`.padStart(5) %></b> issues opened
|
||||
<b><%= `▇▇`.padStart(5) %></b> issue comments
|
||||
|
||||
<b>Tracked activity</b>
|
||||
<b><%= `▇▇`.padStart(5) %></b> users followed
|
||||
<b><%= `▇▇`.padStart(5) %></b> repositories sponsored
|
||||
<b><%= `▇▇`.padStart(5) %></b> repositories starred
|
||||
<b><%= `▇▇`.padStart(5) %></b> repositories watched
|
||||
<% if (plugins.lines) { -%>
|
||||
|
||||
<span class="diff">@@ -▇▇ +▇▇ @@</span>
|
||||
<% } -%></div>
|
||||
<div class="stdin"><span class="ps1-path">▇▇▇▇@metrics</span>:<span class="ps1-location">~</span># ls -lh github/repositories</div><!--
|
||||
--><div class="stdout"><!--
|
||||
-->Total ▇▇ repositories
|
||||
<% if (plugins.traffic) { -%>
|
||||
-r-- <b><%= `▇▇`.padStart(5) %></b> views
|
||||
<% } -%>
|
||||
-r-- <b><%= `▇▇`.padStart(5) %></b> stargazers
|
||||
-r-- <b><%= `▇▇`.padStart(5) %></b> forks
|
||||
-r-- <b><%= `▇▇`.padStart(5) %></b> watchers
|
||||
dr-x <b><%= `▇▇`.padStart(5) %></b> packages
|
||||
dr-x <b><%= `▇▇`.padStart(5) %></b> gists
|
||||
<% if (plugins.followup) { -%>
|
||||
dr-x <b><%= `▇▇`.padStart(5) %></b> ISSUES
|
||||
-r-- <b><%= `▇▇`.padStart(5) %></b> ├── open
|
||||
-r-- <b><%= `▇▇`.padStart(5) %></b> └── closed
|
||||
dr-x <b><%= `▇▇`.padStart(5) %></b> PULL_REQUESTS
|
||||
-r-- <b><%= `▇▇`.padStart(5) %></b> ├── open
|
||||
-r-- <b><%= `▇▇`.padStart(5) %></b> └── merged
|
||||
<% } -%>
|
||||
dr-x LICENSE
|
||||
-r-- └── ▇▇▇▇
|
||||
</div><% if (plugins.languages) { -%>
|
||||
|
||||
<div class="stdin"><span class="ps1-path">▇▇▇▇@metrics</span>:<span class="ps1-location">~</span># locale</div><!--
|
||||
--><div class="stdout"><!--
|
||||
--><% for (const value of [0.6, 0.2, 0.1, 0.05, 0.05, 0, 0, 0]) { -%>
|
||||
<b><%= `▇▇▇▇▇▇`.padEnd(12) %></b> [<%= "#".repeat(Math.ceil(100*value/5)).padEnd(20) %>] ▇%
|
||||
<% } -%></div><% } -%><% if (plugins.pagespeed) { -%>
|
||||
|
||||
<div class="stdin"><span class="ps1-path">▇▇▇▇@metrics</span>:<span class="ps1-location">~</span># curl -I ▇▇▇▇▇▇</div><!--
|
||||
--><div class="stdout"><!--
|
||||
--><b>User-Agent</b>: Google PageSpeed API
|
||||
<b>Location</b>: ▇▇▇▇▇▇
|
||||
<b>X-Performance</b>: ▇%
|
||||
<b>X-Accessibility</b>: ▇%
|
||||
<b>X-Best-Practices</b>: ▇%
|
||||
<b>X-SEO</b>: ▇%</div><% } -%>
|
||||
|
||||
<footer>Connection reset by 127.0.0.1</footer></pre>
|
||||
</div>
|
||||
</foreignObject>
|
||||
</svg>
|
||||
|
||||
|
After Width: | Height: | Size: 3.8 KiB |
@@ -0,0 +1,97 @@
|
||||
query Metrics {
|
||||
user(login: $login) {
|
||||
databaseId
|
||||
name
|
||||
login
|
||||
createdAt
|
||||
avatarUrl
|
||||
websiteUrl
|
||||
gists {
|
||||
totalCount
|
||||
}
|
||||
repositories(last: $repositories, isFork: false, ownerAffiliations: OWNER) {
|
||||
totalCount
|
||||
nodes {
|
||||
name
|
||||
watchers {
|
||||
totalCount
|
||||
}
|
||||
stargazers {
|
||||
totalCount
|
||||
}
|
||||
languages(first: 4) {
|
||||
edges {
|
||||
size
|
||||
node {
|
||||
color
|
||||
name
|
||||
}
|
||||
}
|
||||
}
|
||||
issues_open: issues(states: OPEN) {
|
||||
totalCount
|
||||
}
|
||||
issues_closed: issues(states: CLOSED) {
|
||||
totalCount
|
||||
}
|
||||
pr_open: pullRequests(states: OPEN) {
|
||||
totalCount
|
||||
}
|
||||
pr_merged: pullRequests(states: MERGED) {
|
||||
totalCount
|
||||
}
|
||||
forkCount
|
||||
licenseInfo {
|
||||
spdxId
|
||||
}
|
||||
}
|
||||
}
|
||||
packages {
|
||||
totalCount
|
||||
}
|
||||
starredRepositories {
|
||||
totalCount
|
||||
}
|
||||
watching {
|
||||
totalCount
|
||||
}
|
||||
sponsorshipsAsSponsor {
|
||||
totalCount
|
||||
}
|
||||
sponsorshipsAsMaintainer {
|
||||
totalCount
|
||||
}
|
||||
contributionsCollection {
|
||||
totalRepositoriesWithContributedCommits
|
||||
totalCommitContributions
|
||||
restrictedContributionsCount
|
||||
totalIssueContributions
|
||||
totalPullRequestContributions
|
||||
totalPullRequestReviewContributions
|
||||
}
|
||||
calendar:contributionsCollection(from: $calendar.from, to: $calendar.to) {
|
||||
contributionCalendar {
|
||||
weeks {
|
||||
contributionDays {
|
||||
color
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
repositoriesContributedTo {
|
||||
totalCount
|
||||
}
|
||||
followers {
|
||||
totalCount
|
||||
}
|
||||
following {
|
||||
totalCount
|
||||
}
|
||||
issueComments {
|
||||
totalCount
|
||||
}
|
||||
organizations {
|
||||
totalCount
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,107 @@
|
||||
/* SVG global context */
|
||||
svg {
|
||||
font-family: -apple-system, BlinkMacSystemFont, Segoe UI, Helvetica, Arial, sans-serif, Apple Color Emoji, Segoe UI Emoji;
|
||||
font-size: 14px;
|
||||
color: #777777;
|
||||
}
|
||||
|
||||
/* Title bar */
|
||||
.header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
width: 100%;
|
||||
height: 20px;
|
||||
align-items: center;
|
||||
padding: 0 8px;
|
||||
box-sizing: border-box;
|
||||
border-top-left-radius: 5px;
|
||||
border-top-right-radius: 5px;
|
||||
background: linear-gradient(#504b45 0%,#3c3b37 100%);
|
||||
}
|
||||
|
||||
.title {
|
||||
color: #d5d0ce;
|
||||
line-height: 12px;
|
||||
}
|
||||
|
||||
.buttons {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.button {
|
||||
color: black;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
margin-right: 5px;
|
||||
font-size: 8px;
|
||||
height: 12px;
|
||||
width: 12px;
|
||||
border-radius: 100%;
|
||||
background: linear-gradient(#7d7871 0%, #595953 100%);
|
||||
text-shadow: 0px 1px 0px rgba(255,255,255,0.2);
|
||||
}
|
||||
|
||||
.button.exit {
|
||||
background: linear-gradient(#f37458 0%, #de4c12 100%);
|
||||
}
|
||||
|
||||
/* Terminal */
|
||||
pre {
|
||||
margin: 0;
|
||||
background: #42092B;
|
||||
padding: 12px;
|
||||
border-bottom-left-radius: 5px;
|
||||
border-bottom-right-radius: 5px;
|
||||
font-family: monospace;
|
||||
color: #DDDDDD;
|
||||
}
|
||||
|
||||
.banner, footer {
|
||||
opacity: .7;
|
||||
}
|
||||
|
||||
/* Prompt */
|
||||
.ps1-path {
|
||||
color: #7EDA29;
|
||||
}
|
||||
|
||||
.ps1-location {
|
||||
color: #4878c0;
|
||||
}
|
||||
|
||||
/* Diff */
|
||||
.diff {
|
||||
color: #3A96DD;
|
||||
}
|
||||
|
||||
/* Error */
|
||||
.error {
|
||||
color: #cb2431;
|
||||
}
|
||||
|
||||
/* Animations */
|
||||
.stdin, footer {
|
||||
width: 0%;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
animation-name: stdin-animation;
|
||||
animation-fill-mode: both;
|
||||
}
|
||||
|
||||
.stdout {
|
||||
max-height: 0%;
|
||||
overflow: hidden;
|
||||
animation-name: stdout-animation;
|
||||
animation-fill-mode: both;
|
||||
}
|
||||
|
||||
@keyframes stdin-animation {
|
||||
0% { width: 0%; }
|
||||
100% { width: 100%; }
|
||||
}
|
||||
|
||||
@keyframes stdout-animation {
|
||||
0% { max-height: 0; }
|
||||
100% { max-height: 360px; }
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
//Imports
|
||||
import common from "./../common.mjs"
|
||||
|
||||
/** Template processor */
|
||||
export default async function ({login, q}, {conf, data, rest, graphql, plugins}, {s, pending, imports}) {
|
||||
//Common
|
||||
await common(...arguments)
|
||||
const computed = data.computed
|
||||
|
||||
//Compute image size
|
||||
computed.svg = {height:640, width:480}
|
||||
if (computed.plugins.followup)
|
||||
computed.svg.height += 100 + 32
|
||||
if (computed.plugins.lines)
|
||||
computed.svg.height += 30 + 32
|
||||
if (computed.plugins.traffic)
|
||||
computed.svg.height += 16 + 32
|
||||
if (computed.plugins.pagespeed)
|
||||
computed.svg.height += 136 + 32
|
||||
if (computed.plugins.languages)
|
||||
computed.svg.height += 170 + 32
|
||||
|
||||
//Compute registration date
|
||||
const diff = (Date.now()-(new Date(data.user.createdAt)).getTime())/(365*24*60*60*1000)
|
||||
const years = Math.floor(diff)
|
||||
const months = Math.ceil((diff-years)*12)
|
||||
computed.registration = years ? `${years}y` : `${months}m`
|
||||
|
||||
//Meta
|
||||
data.meta = {
|
||||
version:conf.package.version,
|
||||
$:`<span class="ps1-path">${data.user.login}@metrics</span>:<span class="ps1-location">~</span>${computed.token.scopes.includes("repo") ? "#" : "$"}`,
|
||||
}
|
||||
}
|
||||
+2
-1
@@ -23,7 +23,8 @@
|
||||
//Perform tests
|
||||
await test.build()
|
||||
for (const template of [
|
||||
"classic"
|
||||
"classic",
|
||||
"terminal",
|
||||
]) {
|
||||
for (const q of [
|
||||
{},
|
||||
|
||||
+1
-1
@@ -21,7 +21,7 @@
|
||||
const assets = {}
|
||||
const templates = path.join(__dirname, "..", "src/templates")
|
||||
for (const name of await fs.promises.readdir(templates)) {
|
||||
if (/^index.mjs$/.test(name))
|
||||
if (/.*[.]mjs$/.test(name))
|
||||
continue
|
||||
console.log(`Including template ${name}`)
|
||||
const files = [
|
||||
|
||||
Reference in new issue
Block a user