Fix svg height, add conversion options and options to use differents data from GitHub account (#35)
* Display all features on web instance but disable them when they're not enabled * Resize dynamically SVG output and add support to convert images to jpeg/png * Disable animations when computing height * Add option to disable animations * Add options to specify different data from used GitHub account * Update tests
This commit is contained in:
34
action.yml
34
action.yml
@@ -38,6 +38,20 @@ inputs:
|
|||||||
description: Timezone used by metrics
|
description: Timezone used by metrics
|
||||||
default: ""
|
default: ""
|
||||||
|
|
||||||
|
# Specify output type
|
||||||
|
# Supported values are :
|
||||||
|
# - svg (support animations and transparency)
|
||||||
|
# - png (support transparency)
|
||||||
|
# - jpeg
|
||||||
|
config_output:
|
||||||
|
description: Output image type
|
||||||
|
default: svg
|
||||||
|
|
||||||
|
# Enable or disable SVG animations
|
||||||
|
config_animations:
|
||||||
|
description: Enable or disable SVG animations
|
||||||
|
default: yes
|
||||||
|
|
||||||
# Number of repositories to use for metrics
|
# Number of repositories to use for metrics
|
||||||
# A high number increase metrics accuracy, but will consume additional API requests when using plugins
|
# A high number increase metrics accuracy, but will consume additional API requests when using plugins
|
||||||
repositories:
|
repositories:
|
||||||
@@ -71,11 +85,17 @@ inputs:
|
|||||||
default: "header, activity, community, repositories, metadata"
|
default: "header, activity, community, repositories, metadata"
|
||||||
|
|
||||||
# Google PageSpeed plugin
|
# Google PageSpeed plugin
|
||||||
# Enable it to compute the performance for the website attached to "user"
|
# Enable it to compute the performance of provided website
|
||||||
plugin_pagespeed:
|
plugin_pagespeed:
|
||||||
description: Enable Google PageSpeed metrics for user's website
|
description: Enable Google PageSpeed metrics for user's website
|
||||||
default: no
|
default: no
|
||||||
|
|
||||||
|
# Website to audit with PageSpeed
|
||||||
|
# Leave empty to default to the website attached to "user"'s GitHub account
|
||||||
|
plugin_pagespeed_url:
|
||||||
|
description: Website to audit with PageSpeed
|
||||||
|
default: ""
|
||||||
|
|
||||||
# Display additional PageSpeed audit metrics
|
# Display additional PageSpeed audit metrics
|
||||||
# The following are displayed :
|
# The following are displayed :
|
||||||
# First Contentful Paint, Speed Index, Largest Contentful Paint, Time to Interactive, Total Blocking Time, Cumulative Layout Shift
|
# First Contentful Paint, Speed Index, Largest Contentful Paint, Time to Interactive, Total Blocking Time, Cumulative Layout Shift
|
||||||
@@ -217,6 +237,12 @@ inputs:
|
|||||||
description: Posts external source
|
description: Posts external source
|
||||||
default: ""
|
default: ""
|
||||||
|
|
||||||
|
# Posts source username
|
||||||
|
# Leave empty to default to the login "user"'s GitHub account
|
||||||
|
plugin_posts_user:
|
||||||
|
description: Posts external source username
|
||||||
|
default: ""
|
||||||
|
|
||||||
# Number of posts to display
|
# Number of posts to display
|
||||||
plugin_posts_limit:
|
plugin_posts_limit:
|
||||||
description: Number of posts to display
|
description: Number of posts to display
|
||||||
@@ -297,6 +323,12 @@ inputs:
|
|||||||
description: Display recent tweets
|
description: Display recent tweets
|
||||||
default: no
|
default: no
|
||||||
|
|
||||||
|
# Twitter username
|
||||||
|
# Leave empty to default to the twitter account attached to "user"'s GitHub account
|
||||||
|
plugin_tweets_user:
|
||||||
|
description: Twitter username
|
||||||
|
default: ""
|
||||||
|
|
||||||
# Tweets API token (required when tweets plugin is enabled)
|
# Tweets API token (required when tweets plugin is enabled)
|
||||||
# See https://apps.twitter.com for more informations
|
# See https://apps.twitter.com for more informations
|
||||||
plugin_tweets_token:
|
plugin_tweets_token:
|
||||||
|
|||||||
@@ -43,7 +43,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
//Load configuration
|
//Load configuration
|
||||||
const {conf, Plugins, Templates} = await setup({log:false})
|
const {conf, Plugins, Templates} = await setup({log:false, nosettings:true})
|
||||||
info("Setup", "complete")
|
info("Setup", "complete")
|
||||||
info("Version", conf.package.version)
|
info("Version", conf.package.version)
|
||||||
|
|
||||||
@@ -110,9 +110,13 @@
|
|||||||
|
|
||||||
//Config
|
//Config
|
||||||
const config = {
|
const config = {
|
||||||
"config.timezone":input.string("config_timezone")
|
"config.timezone":input.string("config_timezone"),
|
||||||
|
"config.output":input.string("config_output"),
|
||||||
|
"config.animations":input.bool("config_animations"),
|
||||||
}
|
}
|
||||||
info("Timezone", config["config.timezone"] ?? "(system default)")
|
info("Timezone", config["config.timezone"] ?? "(system default)")
|
||||||
|
info("Convert SVG", config["config.output"] ?? "(no)")
|
||||||
|
info("Enable SVG animations", config["config.animations"])
|
||||||
|
|
||||||
//Additional plugins
|
//Additional plugins
|
||||||
const plugins = {
|
const plugins = {
|
||||||
@@ -137,6 +141,8 @@
|
|||||||
if (plugins.pagespeed.enabled) {
|
if (plugins.pagespeed.enabled) {
|
||||||
plugins.pagespeed.token = input.string("plugin_pagespeed_token")
|
plugins.pagespeed.token = input.string("plugin_pagespeed_token")
|
||||||
info("Pagespeed token", plugins.pagespeed.token, {token:true})
|
info("Pagespeed token", plugins.pagespeed.token, {token:true})
|
||||||
|
for (const option of ["url"])
|
||||||
|
info(`Pagespeed ${option}`, q[`pagespeed.${option}`] = input.string(`plugin_pagespeed_${option}`))
|
||||||
for (const option of ["detailed", "screenshot"])
|
for (const option of ["detailed", "screenshot"])
|
||||||
info(`Pagespeed ${option}`, q[`pagespeed.${option}`] = input.bool(`plugin_pagespeed_${option}`))
|
info(`Pagespeed ${option}`, q[`pagespeed.${option}`] = input.bool(`plugin_pagespeed_${option}`))
|
||||||
}
|
}
|
||||||
@@ -163,7 +169,7 @@
|
|||||||
}
|
}
|
||||||
//Posts
|
//Posts
|
||||||
if (plugins.posts.enabled) {
|
if (plugins.posts.enabled) {
|
||||||
for (const option of ["source"])
|
for (const option of ["source", "user"])
|
||||||
info(`Posts ${option}`, q[`posts.${option}`] = input.string(`plugin_posts_${option}`))
|
info(`Posts ${option}`, q[`posts.${option}`] = input.string(`plugin_posts_${option}`))
|
||||||
for (const option of ["limit"])
|
for (const option of ["limit"])
|
||||||
info(`Posts ${option}`, q[`posts.${option}`] = input.number(`plugin_posts_${option}`))
|
info(`Posts ${option}`, q[`posts.${option}`] = input.number(`plugin_posts_${option}`))
|
||||||
@@ -191,6 +197,8 @@
|
|||||||
if (plugins.tweets.enabled) {
|
if (plugins.tweets.enabled) {
|
||||||
plugins.tweets.token = input.string("plugin_tweets_token")
|
plugins.tweets.token = input.string("plugin_tweets_token")
|
||||||
info("Tweets token", plugins.tweets.token, {token:true})
|
info("Tweets token", plugins.tweets.token, {token:true})
|
||||||
|
for (const option of ["user"])
|
||||||
|
info(`Tweets ${option}`, q[`tweets.${option}`] = input.string(`plugin_tweets_${option}`))
|
||||||
for (const option of ["limit"])
|
for (const option of ["limit"])
|
||||||
info(`Tweets ${option}`, q[`tweets.${option}`] = input.number(`plugin_tweets_${option}`))
|
info(`Tweets ${option}`, q[`tweets.${option}`] = input.number(`plugin_tweets_${option}`))
|
||||||
}
|
}
|
||||||
@@ -209,7 +217,7 @@
|
|||||||
q = {...query, ...q, base:false, ...base, ...config, repositories, template}
|
q = {...query, ...q, base:false, ...base, ...config, repositories, template}
|
||||||
|
|
||||||
//Render metrics
|
//Render metrics
|
||||||
const rendered = await metrics({login:user, q, dflags}, {graphql, rest, plugins, conf, die, verify}, {Plugins, Templates})
|
const {rendered} = await metrics({login:user, q, dflags}, {graphql, rest, plugins, conf, die, verify}, {Plugins, Templates})
|
||||||
info("Rendering", "complete")
|
info("Rendering", "complete")
|
||||||
|
|
||||||
//Commit to repository
|
//Commit to repository
|
||||||
|
|||||||
@@ -12,7 +12,7 @@
|
|||||||
import SVGO from "svgo"
|
import SVGO from "svgo"
|
||||||
|
|
||||||
//Setup
|
//Setup
|
||||||
export default async function metrics({login, q, dflags = []}, {graphql, rest, plugins, conf, die = false, verify = false}, {Plugins, Templates}) {
|
export default async function metrics({login, q, dflags = []}, {graphql, rest, plugins, conf, die = false, verify = false, convert = null}, {Plugins, Templates}) {
|
||||||
//Compute rendering
|
//Compute rendering
|
||||||
try {
|
try {
|
||||||
|
|
||||||
@@ -27,7 +27,7 @@
|
|||||||
throw new Error("unsupported template")
|
throw new Error("unsupported template")
|
||||||
const {image, style, fonts} = conf.templates[template]
|
const {image, style, fonts} = conf.templates[template]
|
||||||
const queries = conf.queries
|
const queries = conf.queries
|
||||||
const data = {base:{}, config:{}, errors:[], plugins:{}, computed:{}}
|
const data = {animated:true, base:{}, config:{}, errors:[], plugins:{}, computed:{}}
|
||||||
|
|
||||||
//Base parts
|
//Base parts
|
||||||
{
|
{
|
||||||
@@ -83,7 +83,12 @@
|
|||||||
//Template rendering
|
//Template rendering
|
||||||
console.debug(`metrics/compute/${login} > render`)
|
console.debug(`metrics/compute/${login} > render`)
|
||||||
let rendered = await ejs.render(image, {...data, s, style, fonts}, {async:true})
|
let rendered = await ejs.render(image, {...data, s, style, fonts}, {async:true})
|
||||||
|
//Apply resizing
|
||||||
|
const {resized, mime} = await svgresize(rendered, {convert})
|
||||||
|
rendered = resized
|
||||||
|
|
||||||
|
//Additional SVG transformations
|
||||||
|
if (/svg/.test(mime)) {
|
||||||
//Optimize rendering
|
//Optimize rendering
|
||||||
if ((conf.optimize)&&(!q.raw)) {
|
if ((conf.optimize)&&(!q.raw)) {
|
||||||
console.debug(`metrics/compute/${login} > optimize`)
|
console.debug(`metrics/compute/${login} > optimize`)
|
||||||
@@ -91,7 +96,6 @@
|
|||||||
const {data:optimized} = await svgo.optimize(rendered)
|
const {data:optimized} = await svgo.optimize(rendered)
|
||||||
rendered = optimized
|
rendered = optimized
|
||||||
}
|
}
|
||||||
|
|
||||||
//Verify svg
|
//Verify svg
|
||||||
if (verify) {
|
if (verify) {
|
||||||
console.debug(`metrics/compute/${login} > verify SVG`)
|
console.debug(`metrics/compute/${login} > verify SVG`)
|
||||||
@@ -100,10 +104,11 @@
|
|||||||
if (parsed.errors.length)
|
if (parsed.errors.length)
|
||||||
throw new Error(`Malformed SVG : \n${parsed.errors.join("\n")}`)
|
throw new Error(`Malformed SVG : \n${parsed.errors.join("\n")}`)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
//Result
|
//Result
|
||||||
console.debug(`metrics/compute/${login} > success`)
|
console.debug(`metrics/compute/${login} > success`)
|
||||||
return rendered
|
return {rendered, mime}
|
||||||
}
|
}
|
||||||
//Internal error
|
//Internal error
|
||||||
catch (error) {
|
catch (error) {
|
||||||
@@ -174,6 +179,45 @@
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Render svg */
|
||||||
|
async function svgresize(svg, {convert} = {}) {
|
||||||
|
//Instantiate browser if needed
|
||||||
|
if (!svgresize.browser) {
|
||||||
|
svgresize.browser = await puppeteer.launch({headless:true, executablePath:process.env.PUPPETEER_BROWSER_PATH, args:["--no-sandbox", "--disable-extensions", "--disable-setuid-sandbox", "--disable-dev-shm-usage"]})
|
||||||
|
console.debug(`metrics/svgresize > started ${await svgresize.browser.version()}`)
|
||||||
|
}
|
||||||
|
//Render through browser and resize height
|
||||||
|
const page = await svgresize.browser.newPage()
|
||||||
|
await page.setContent(svg, {waitUntil:"load"})
|
||||||
|
let mime = "image/svg+xml"
|
||||||
|
let {resized, width, height} = await page.evaluate(async () => {
|
||||||
|
//Disable animations
|
||||||
|
const animated = !document.querySelector("svg").classList.contains("no-animations")
|
||||||
|
if (animated)
|
||||||
|
document.querySelector("svg").classList.add("no-animations")
|
||||||
|
//Get bounds and resize
|
||||||
|
let {y:height, width} = document.querySelector("svg #metrics-end").getBoundingClientRect()
|
||||||
|
height = Math.ceil(height)
|
||||||
|
width = Math.ceil(width)
|
||||||
|
//Resize svg
|
||||||
|
document.querySelector("svg").setAttribute("height", height)
|
||||||
|
//Enable animations
|
||||||
|
if (animated)
|
||||||
|
document.querySelector("svg").classList.remove("no-animations")
|
||||||
|
//Result
|
||||||
|
return {resized:new XMLSerializer().serializeToString(document.querySelector("svg")), height, width}
|
||||||
|
})
|
||||||
|
//Convert if required
|
||||||
|
if (convert) {
|
||||||
|
console.debug(`metrics/svgresize > convert to ${convert}`)
|
||||||
|
resized = await page.screenshot({type:convert, clip:{x:0, y:0, width, height}, omitBackground:true})
|
||||||
|
mime = `image/${convert}`
|
||||||
|
}
|
||||||
|
//Result
|
||||||
|
await page.close()
|
||||||
|
return {resized, mime}
|
||||||
|
}
|
||||||
|
|
||||||
/** Placeholder generator */
|
/** Placeholder generator */
|
||||||
function placeholder({data, conf, q}) {
|
function placeholder({data, conf, q}) {
|
||||||
//Proxifier
|
//Proxifier
|
||||||
|
|||||||
@@ -7,7 +7,7 @@
|
|||||||
const Plugins = {}
|
const Plugins = {}
|
||||||
|
|
||||||
/** Setup */
|
/** Setup */
|
||||||
export default async function ({log = true} = {}) {
|
export default async function ({log = true, nosettings = false} = {}) {
|
||||||
|
|
||||||
//Paths
|
//Paths
|
||||||
const __metrics = path.join(path.dirname(url.fileURLToPath(import.meta.url)), "../..")
|
const __metrics = path.join(path.dirname(url.fileURLToPath(import.meta.url)), "../..")
|
||||||
@@ -33,9 +33,13 @@
|
|||||||
//Load settings
|
//Load settings
|
||||||
logger(`metrics/setup > load settings.json`)
|
logger(`metrics/setup > load settings.json`)
|
||||||
if (fs.existsSync(__settings)) {
|
if (fs.existsSync(__settings)) {
|
||||||
|
if (nosettings)
|
||||||
|
logger(`metrics/setup > load settings.json > skipped because no settings is enabled`)
|
||||||
|
else {
|
||||||
conf.settings = JSON.parse(`${await fs.promises.readFile(__settings)}`)
|
conf.settings = JSON.parse(`${await fs.promises.readFile(__settings)}`)
|
||||||
logger(`metrics/setup > load settings.json > success`)
|
logger(`metrics/setup > load settings.json > success`)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
else
|
else
|
||||||
logger(`metrics/setup > load settings.json > (missing)`)
|
logger(`metrics/setup > load settings.json > (missing)`)
|
||||||
if (!conf.settings.templates)
|
if (!conf.settings.templates)
|
||||||
|
|||||||
@@ -2,4 +2,4 @@
|
|||||||
import app from "./instance.mjs"
|
import app from "./instance.mjs"
|
||||||
|
|
||||||
//Start app
|
//Start app
|
||||||
await app({mock:process.env.USE_MOCKED_DATA})
|
await app({mock:process.env.USE_MOCKED_DATA, nosettings:process.env.NO_SETTINGS})
|
||||||
@@ -11,11 +11,12 @@
|
|||||||
import metrics from "../metrics.mjs"
|
import metrics from "../metrics.mjs"
|
||||||
|
|
||||||
/** App */
|
/** App */
|
||||||
export default async function ({mock = false} = {}) {
|
export default async function ({mock = false, nosettings = false} = {}) {
|
||||||
|
|
||||||
//Load configuration settings
|
//Load configuration settings
|
||||||
const {conf, Plugins, Templates} = await setup()
|
const {conf, Plugins, Templates} = await setup({nosettings})
|
||||||
const {token, maxusers = 0, restricted = [], debug = false, cached = 30*60*1000, port = 3000, ratelimiter = null, plugins = null} = conf.settings
|
const {token, maxusers = 0, restricted = [], debug = false, cached = 30*60*1000, port = 3000, ratelimiter = null, plugins = null} = conf.settings
|
||||||
|
cache.placeholder = new Map()
|
||||||
|
|
||||||
//Apply configuration mocking if needed
|
//Apply configuration mocking if needed
|
||||||
if (mock) {
|
if (mock) {
|
||||||
@@ -66,8 +67,8 @@
|
|||||||
|
|
||||||
//Base routes
|
//Base routes
|
||||||
const limiter = ratelimit({max:debug ? Number.MAX_SAFE_INTEGER : 60, windowMs:60*1000})
|
const limiter = ratelimit({max:debug ? Number.MAX_SAFE_INTEGER : 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 templates = Object.entries(Templates).map(([name]) => ({name, enabled:(conf.settings.templates.enabled.length ? conf.settings.templates.enabled.includes(name) : true) ?? false}))
|
||||||
const enabled = Object.entries(plugins).filter(([key, plugin]) => plugin.enabled).map(([key]) => key)
|
const enabled = Object.entries(Plugins).map(([name]) => ({name, enabled:plugins[name].enabled ?? false}))
|
||||||
const actions = {flush:new Map()}
|
const actions = {flush:new Map()}
|
||||||
app.get("/", limiter, (req, res) => res.sendFile(`${conf.statics}/index.html`))
|
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("/index.html", limiter, (req, res) => res.sendFile(`${conf.statics}/index.html`))
|
||||||
@@ -117,9 +118,18 @@
|
|||||||
return res.sendStatus(403)
|
return res.sendStatus(403)
|
||||||
}
|
}
|
||||||
//Read cached data if possible
|
//Read cached data if possible
|
||||||
|
//Placeholder
|
||||||
|
if ((login === "placeholder")&&(cache.placeholder.has(Object.keys(req.query).sort().join("-")))) {
|
||||||
|
const {rendered, mime} = cache.placeholder.get(Object.keys(req.query).sort().join("-"))
|
||||||
|
res.header("Content-Type", mime)
|
||||||
|
res.send(rendered)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
//User cached
|
||||||
if ((!debug)&&(cached)&&(cache.get(login))) {
|
if ((!debug)&&(cached)&&(cache.get(login))) {
|
||||||
res.header("Content-Type", "image/svg+xml")
|
const {rendered, mime} = cache.get(login)
|
||||||
res.send(cache.get(login))
|
res.header("Content-Type", mime)
|
||||||
|
res.send(rendered)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
//Maximum simultaneous users
|
//Maximum simultaneous users
|
||||||
@@ -133,12 +143,19 @@
|
|||||||
//Render
|
//Render
|
||||||
console.debug(`metrics/app/${login} > ${util.inspect(req.query, {depth:Infinity, maxStringLength:256})}`)
|
console.debug(`metrics/app/${login} > ${util.inspect(req.query, {depth:Infinity, maxStringLength:256})}`)
|
||||||
const q = parse(req.query)
|
const q = parse(req.query)
|
||||||
const rendered = await metrics({login, q}, {graphql, rest, plugins, conf, die:q["plugins.errors.fatal"] ?? false, verify:q["verify"] ?? false}, {Plugins, Templates})
|
const {rendered, mime} = await metrics({login, q}, {
|
||||||
|
graphql, rest, plugins, conf,
|
||||||
|
die:q["plugins.errors.fatal"] ?? false,
|
||||||
|
verify:q["verify"] ?? false,
|
||||||
|
convert:["jpeg", "png"].includes(q["config.output"]) ? q["config.output"] : null
|
||||||
|
}, {Plugins, Templates})
|
||||||
//Cache
|
//Cache
|
||||||
if ((!debug)&&(cached)&&(login !== "placeholder"))
|
if (login === "placeholder")
|
||||||
cache.put(login, rendered, cached)
|
cache.placeholder.set(Object.keys(req.query).sort().join("-"), rendered)
|
||||||
|
if ((!debug)&&(cached))
|
||||||
|
cache.put(login, {rendered, mime}, cached)
|
||||||
//Send response
|
//Send response
|
||||||
res.header("Content-Type", "image/svg+xml")
|
res.header("Content-Type", mime)
|
||||||
res.send(rendered)
|
res.send(rendered)
|
||||||
}
|
}
|
||||||
//Internal error
|
//Internal error
|
||||||
@@ -167,7 +184,7 @@
|
|||||||
`Cached time │ ${cached} seconds`,
|
`Cached time │ ${cached} seconds`,
|
||||||
`Rate limiter │ ${ratelimiter ? util.inspect(ratelimiter, {depth:Infinity, maxStringLength:256}) : "(enabled)"}`,
|
`Rate limiter │ ${ratelimiter ? util.inspect(ratelimiter, {depth:Infinity, maxStringLength:256}) : "(enabled)"}`,
|
||||||
`Max simultaneous users │ ${maxusers ? `${maxusers} users` : "(unrestricted)"}`,
|
`Max simultaneous users │ ${maxusers ? `${maxusers} users` : "(unrestricted)"}`,
|
||||||
`Plugins enabled │ ${enabled.join(", ")}`,
|
`Plugins enabled │ ${enabled.map(({name}) => name).join(", ")}`,
|
||||||
`Server ready !`
|
`Server ready !`
|
||||||
].join("\n")))
|
].join("\n")))
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -75,7 +75,7 @@
|
|||||||
},
|
},
|
||||||
templates:{
|
templates:{
|
||||||
list:templates,
|
list:templates,
|
||||||
selected:url.get("template") || templates[0],
|
selected:url.get("template") || templates[0].name,
|
||||||
loaded:{},
|
loaded:{},
|
||||||
placeholder:"",
|
placeholder:"",
|
||||||
descriptions:{
|
descriptions:{
|
||||||
|
|||||||
@@ -28,9 +28,9 @@
|
|||||||
<div class="step">
|
<div class="step">
|
||||||
<h2>2. Select a template</h2>
|
<h2>2. Select a template</h2>
|
||||||
<div class="templates">
|
<div class="templates">
|
||||||
<label v-for="template in templates.list" :key="template" v-show="templates.descriptions[template] !== '(hidden)'">
|
<label v-for="template in templates.list" :key="template" v-show="templates.descriptions[template.name] !== '(hidden)'" :class="{'not-available':!template.enabled}" :title="!template.enabled ? 'This template is not enabled on web instance, use it with GitHub actions !' : ''">
|
||||||
<input type="radio" v-model="templates.selected" :value="template" @change="load" :disabled="generated.pending">
|
<input type="radio" v-model="templates.selected" :value="template.name" @change="load" :disabled="generated.pending">
|
||||||
{{ templates.descriptions[template] || template }}
|
{{ templates.descriptions[template.name] || template.name }}
|
||||||
</label>
|
</label>
|
||||||
</div>
|
</div>
|
||||||
<template v-if="plugins.base.length">
|
<template v-if="plugins.base.length">
|
||||||
@@ -45,12 +45,11 @@
|
|||||||
<template v-if="plugins.list.length">
|
<template v-if="plugins.list.length">
|
||||||
<h3>2.2 Enable additional plugins</h3>
|
<h3>2.2 Enable additional plugins</h3>
|
||||||
<div class="plugins">
|
<div class="plugins">
|
||||||
<label v-for="plugin in plugins.list" :key="plugin">
|
<label v-for="plugin in plugins.list" :key="plugin" :class="{'not-available':!plugin.enabled}" :title="!plugin.enabled ? 'This plugin is not enabled on web instance, use it with GitHub actions !' : ''">
|
||||||
<input type="checkbox" v-model="plugins.enabled[plugin]" @change="load" :disabled="generated.pending">
|
<input type="checkbox" v-model="plugins.enabled[plugin.name]" @change="load" :disabled="(!plugin.enabled)||(generated.pending)">
|
||||||
{{ plugins.descriptions[plugin] || plugin }}
|
{{ plugins.descriptions[plugin.name] || plugin.name }}
|
||||||
</label>
|
</label>
|
||||||
</div>
|
</div>
|
||||||
<i>*Additional plugins may be available when used as GitHub Action</i>
|
|
||||||
<template v-if="(plugins.enabled.tweets)||(plugins.enabled.music)||(plugins.enabled.pagespeed)||(plugins.enabled.languages)||(plugins.enabled.habits)||(plugins.enabled.posts)||(plugins.enabled.isocalendar)||(plugins.enabled.projects)||(plugins.enabled.topics)">
|
<template v-if="(plugins.enabled.tweets)||(plugins.enabled.music)||(plugins.enabled.pagespeed)||(plugins.enabled.languages)||(plugins.enabled.habits)||(plugins.enabled.posts)||(plugins.enabled.isocalendar)||(plugins.enabled.projects)||(plugins.enabled.topics)">
|
||||||
<h3>2.3 Configure additional plugins</h3>
|
<h3>2.3 Configure additional plugins</h3>
|
||||||
<div class="options">
|
<div class="options">
|
||||||
@@ -58,59 +57,59 @@
|
|||||||
<h4>{{ plugins.descriptions.tweets }}</h4>
|
<h4>{{ plugins.descriptions.tweets }}</h4>
|
||||||
<label>
|
<label>
|
||||||
Number of tweets to display
|
Number of tweets to display
|
||||||
<input type="number" v-model="plugins.options['tweets.limit']" min="1" max="10" @change="load">
|
<input type="number" v-model="plugins.options['tweets.limit']" min="1" max="10" @change="load" :disabled="generated.pending">
|
||||||
</label>
|
</label>
|
||||||
</div>
|
</div>
|
||||||
<div class="options-group" v-if="plugins.enabled.music">
|
<div class="options-group" v-if="plugins.enabled.music">
|
||||||
<h4>{{ plugins.descriptions.music }}</h4>
|
<h4>{{ plugins.descriptions.music }}</h4>
|
||||||
<label>
|
<label>
|
||||||
Playlist embed link
|
Playlist embed link
|
||||||
<input type="text" v-model="plugins.options['music.playlist']" placeholder="https://embed.music.apple.com/en/playlist/">
|
<input type="text" v-model="plugins.options['music.playlist']" placeholder="https://embed.music.apple.com/en/playlist/" :disabled="generated.pending">
|
||||||
</label>
|
</label>
|
||||||
<label>
|
<label>
|
||||||
Number of tracks to display
|
Number of tracks to display
|
||||||
<input type="number" v-model="plugins.options['music.limit']" min="1" @change="load">
|
<input type="number" v-model="plugins.options['music.limit']" min="1" @change="load" :disabled="generated.pending">
|
||||||
</label>
|
</label>
|
||||||
</div>
|
</div>
|
||||||
<div class="options-group" v-if="plugins.enabled.pagespeed">
|
<div class="options-group" v-if="plugins.enabled.pagespeed">
|
||||||
<h4>{{ plugins.descriptions.pagespeed }}</h4>
|
<h4>{{ plugins.descriptions.pagespeed }}</h4>
|
||||||
<label>
|
<label>
|
||||||
Detailed PageSpeed report
|
Detailed PageSpeed report
|
||||||
<input type="checkbox" v-model="plugins.options['pagespeed.detailed']" @change="load">
|
<input type="checkbox" v-model="plugins.options['pagespeed.detailed']" @change="load" :disabled="generated.pending">
|
||||||
</label>
|
</label>
|
||||||
<label>
|
<label>
|
||||||
Include a website screenshot
|
Include a website screenshot
|
||||||
<input type="checkbox" v-model="plugins.options['pagespeed.screenshot']" @change="load">
|
<input type="checkbox" v-model="plugins.options['pagespeed.screenshot']" @change="load" :disabled="generated.pending">
|
||||||
</label>
|
</label>
|
||||||
</div>
|
</div>
|
||||||
<div class="options-group" v-if="plugins.enabled.languages">
|
<div class="options-group" v-if="plugins.enabled.languages">
|
||||||
<h4>{{ plugins.descriptions.languages }}</h4>
|
<h4>{{ plugins.descriptions.languages }}</h4>
|
||||||
<label>
|
<label>
|
||||||
Ignored languages (comma separated)
|
Ignored languages (comma separated)
|
||||||
<input type="text" v-model="plugins.options['languages.ignored']" @change="load">
|
<input type="text" v-model="plugins.options['languages.ignored']" @change="load" :disabled="generated.pending">
|
||||||
</label>
|
</label>
|
||||||
<label>
|
<label>
|
||||||
Skipped repositories (comma separated)
|
Skipped repositories (comma separated)
|
||||||
<input type="text" v-model="plugins.options['languages.skipped']" @change="load">
|
<input type="text" v-model="plugins.options['languages.skipped']" @change="load" :disabled="generated.pending">
|
||||||
</label>
|
</label>
|
||||||
</div>
|
</div>
|
||||||
<div class="options-group" v-if="plugins.enabled.habits">
|
<div class="options-group" v-if="plugins.enabled.habits">
|
||||||
<h4>{{ plugins.descriptions.habits }}</h4>
|
<h4>{{ plugins.descriptions.habits }}</h4>
|
||||||
<label>
|
<label>
|
||||||
Number of events for habits
|
Number of events for habits
|
||||||
<input type="number" v-model="plugins.options['habits.from']" min="1" max="1000">
|
<input type="number" v-model="plugins.options['habits.from']" min="1" max="1000" :disabled="generated.pending">
|
||||||
</label>
|
</label>
|
||||||
<label>
|
<label>
|
||||||
Number of days for habits
|
Number of days for habits
|
||||||
<input type="number" v-model="plugins.options['habits.days']" min="1" max="30">
|
<input type="number" v-model="plugins.options['habits.days']" min="1" max="30" :disabled="generated.pending">
|
||||||
</label>
|
</label>
|
||||||
<label>
|
<label>
|
||||||
Display tidbits
|
Display tidbits
|
||||||
<input type="checkbox" v-model="plugins.options['habits.facts']" @change="load">
|
<input type="checkbox" v-model="plugins.options['habits.facts']" @change="load" :disabled="generated.pending">
|
||||||
</label>
|
</label>
|
||||||
<label>
|
<label>
|
||||||
Display activity charts
|
Display activity charts
|
||||||
<input type="checkbox" v-model="plugins.options['habits.charts']" @change="load">
|
<input type="checkbox" v-model="plugins.options['habits.charts']" @change="load" :disabled="generated.pending">
|
||||||
</label>
|
</label>
|
||||||
</div>
|
</div>
|
||||||
<div class="options-group" v-if="plugins.enabled.posts">
|
<div class="options-group" v-if="plugins.enabled.posts">
|
||||||
@@ -123,14 +122,14 @@
|
|||||||
</label>
|
</label>
|
||||||
<label>
|
<label>
|
||||||
Number of posts to display
|
Number of posts to display
|
||||||
<input type="number" v-model="plugins.options['posts.limit']" min="1" @change="load">
|
<input type="number" v-model="plugins.options['posts.limit']" min="1" @change="load" :disabled="generated.pending">
|
||||||
</label>
|
</label>
|
||||||
</div>
|
</div>
|
||||||
<div class="options-group" v-if="plugins.enabled.isocalendar">
|
<div class="options-group" v-if="plugins.enabled.isocalendar">
|
||||||
<h4>{{ plugins.descriptions.isocalendar }}</h4>
|
<h4>{{ plugins.descriptions.isocalendar }}</h4>
|
||||||
<label>
|
<label>
|
||||||
Isocalendar duration
|
Isocalendar duration
|
||||||
<select v-model="plugins.options['isocalendar.duration']">
|
<select v-model="plugins.options['isocalendar.duration']" :disabled="generated.pending">
|
||||||
<option value="half-year">Half year</option>
|
<option value="half-year">Half year</option>
|
||||||
<option value="full-year">Full year</option>
|
<option value="full-year">Full year</option>
|
||||||
</select>
|
</select>
|
||||||
@@ -140,14 +139,14 @@
|
|||||||
<h4>{{ plugins.descriptions.topics }}</h4>
|
<h4>{{ plugins.descriptions.topics }}</h4>
|
||||||
<label>
|
<label>
|
||||||
Topics display mode
|
Topics display mode
|
||||||
<select v-model="plugins.options['topics.mode']" @change="load">
|
<select v-model="plugins.options['topics.mode']" @change="load" :disabled="generated.pending">
|
||||||
<option value="starred">Starred topics</option>
|
<option value="starred">Starred topics</option>
|
||||||
<option value="mastered">Known and mastered technologies</option>
|
<option value="mastered">Known and mastered technologies</option>
|
||||||
</select>
|
</select>
|
||||||
</label>
|
</label>
|
||||||
<label>
|
<label>
|
||||||
Topics sorting
|
Topics sorting
|
||||||
<select v-model="plugins.options['topics.sort']">
|
<select v-model="plugins.options['topics.sort']" :disabled="generated.pending">
|
||||||
<option value="starred">Recently starred by you</option>
|
<option value="starred">Recently starred by you</option>
|
||||||
<option value="stars">Most stars</option>
|
<option value="stars">Most stars</option>
|
||||||
<option value="activity">Recent actity</option>
|
<option value="activity">Recent actity</option>
|
||||||
@@ -156,18 +155,18 @@
|
|||||||
</label>
|
</label>
|
||||||
<label>
|
<label>
|
||||||
Number of topics to display
|
Number of topics to display
|
||||||
<input type="number" v-model="plugins.options['topics.limit']" @change="load">
|
<input type="number" v-model="plugins.options['topics.limit']" @change="load" :disabled="generated.pending">
|
||||||
</label>
|
</label>
|
||||||
</div>
|
</div>
|
||||||
<div class="options-group" v-if="plugins.enabled.projects">
|
<div class="options-group" v-if="plugins.enabled.projects">
|
||||||
<h4>{{ plugins.descriptions.projects }}</h4>
|
<h4>{{ plugins.descriptions.projects }}</h4>
|
||||||
<label>
|
<label>
|
||||||
Number of projects to display
|
Number of projects to display
|
||||||
<input type="number" v-model="plugins.options['projects.limit']" min="1" max="100" @change="load">
|
<input type="number" v-model="plugins.options['projects.limit']" min="1" max="100" @change="load" :disabled="generated.pending">
|
||||||
</label>
|
</label>
|
||||||
<label>
|
<label>
|
||||||
Repositories projects to display (comma separated)
|
Repositories projects to display (comma separated)
|
||||||
<input type="text" v-model="plugins.options['projects.repositories']" @change="load">
|
<input type="text" v-model="plugins.options['projects.repositories']" @change="load" :disabled="generated.pending">
|
||||||
</label>
|
</label>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -82,6 +82,9 @@
|
|||||||
transition: background-color .4s;
|
transition: background-color .4s;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
}
|
}
|
||||||
|
.not-available {
|
||||||
|
opacity: .3;
|
||||||
|
}
|
||||||
/* Generator */
|
/* Generator */
|
||||||
.generator {
|
.generator {
|
||||||
display: flex;
|
display: flex;
|
||||||
|
|||||||
@@ -6,11 +6,10 @@
|
|||||||
if ((!enabled)||(!q.pagespeed)||(!data.user.websiteUrl))
|
if ((!enabled)||(!q.pagespeed)||(!data.user.websiteUrl))
|
||||||
return null
|
return null
|
||||||
//Parameters override
|
//Parameters override
|
||||||
let {"pagespeed.detailed":detailed = false, "pagespeed.screenshot":screenshot = false} = q
|
let {"pagespeed.detailed":detailed = false, "pagespeed.screenshot":screenshot = false, "pagespeed.url":url = data.user.websiteUrl} = q
|
||||||
//Duration in days
|
//Duration in days
|
||||||
detailed = !!detailed
|
detailed = !!detailed
|
||||||
//Format url if needed
|
//Format url if needed
|
||||||
let url = data.user.websiteUrl
|
|
||||||
if (!/^https?:[/][/]/.test(url))
|
if (!/^https?:[/][/]/.test(url))
|
||||||
url = `https://${url}`
|
url = `https://${url}`
|
||||||
const result = {url, detailed, scores:[], metrics:{}}
|
const result = {url, detailed, scores:[], metrics:{}}
|
||||||
|
|||||||
@@ -1,13 +1,12 @@
|
|||||||
//Setup
|
//Setup
|
||||||
export default async function ({imports, data, q}, {enabled = false} = {}) {
|
export default async function ({login, imports, q}, {enabled = false} = {}) {
|
||||||
//Plugin execution
|
//Plugin execution
|
||||||
try {
|
try {
|
||||||
//Check if plugin is enabled and requirements are met
|
//Check if plugin is enabled and requirements are met
|
||||||
if ((!enabled)||(!q.posts))
|
if ((!enabled)||(!q.posts))
|
||||||
return null
|
return null
|
||||||
//Parameters override
|
//Parameters override
|
||||||
const login = data.user.login
|
let {"posts.source":source = "", "posts.limit":limit = 4, "posts.user":user = login} = q
|
||||||
let {"posts.source":source = "", "posts.limit":limit = 4} = q
|
|
||||||
//Limit
|
//Limit
|
||||||
limit = Math.max(1, Math.min(30, Number(limit)))
|
limit = Math.max(1, Math.min(30, Number(limit)))
|
||||||
//Retrieve posts
|
//Retrieve posts
|
||||||
@@ -17,7 +16,7 @@
|
|||||||
//Dev.to
|
//Dev.to
|
||||||
case "dev.to":{
|
case "dev.to":{
|
||||||
console.debug(`metrics/compute/${login}/plugins > posts > querying api`)
|
console.debug(`metrics/compute/${login}/plugins > posts > querying api`)
|
||||||
posts = (await imports.axios.get(`https://dev.to/api/articles?username=${login}&state=fresh`)).data.map(({title, readable_publish_date:date}) => ({title, date}))
|
posts = (await imports.axios.get(`https://dev.to/api/articles?username=${user}&state=fresh`)).data.map(({title, readable_publish_date:date}) => ({title, date}))
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
//Unsupported
|
//Unsupported
|
||||||
|
|||||||
@@ -6,11 +6,10 @@
|
|||||||
if ((!enabled)||(!q.tweets))
|
if ((!enabled)||(!q.tweets))
|
||||||
return null
|
return null
|
||||||
//Parameters override
|
//Parameters override
|
||||||
let {"tweets.limit":limit = 2} = q
|
let {"tweets.limit":limit = 2, "tweets.user":username = data.user.twitterUsername} = q
|
||||||
//Limit
|
//Limit
|
||||||
limit = Math.max(1, Math.min(10, Number(limit)))
|
limit = Math.max(1, Math.min(10, Number(limit)))
|
||||||
//Load user profile
|
//Load user profile
|
||||||
const username = data.user.twitterUsername
|
|
||||||
console.debug(`metrics/compute/${login}/plugins > tweets > loading twitter profile (@${username})`)
|
console.debug(`metrics/compute/${login}/plugins > tweets > loading twitter profile (@${username})`)
|
||||||
const {data:{data:profile = null}} = await imports.axios.get(`https://api.twitter.com/2/users/by/username/${username}?user.fields=profile_image_url,verified`, {headers:{Authorization:`Bearer ${token}`}})
|
const {data:{data:profile = null}} = await imports.axios.get(`https://api.twitter.com/2/users/by/username/${username}?user.fields=profile_image_url,verified`, {headers:{Authorization:`Bearer ${token}`}})
|
||||||
//Load tweets
|
//Load tweets
|
||||||
|
|||||||
@@ -1,22 +1,4 @@
|
|||||||
<svg xmlns="http://www.w3.org/2000/svg" width="480" height="<%= 12
|
<svg xmlns="http://www.w3.org/2000/svg" width="480" height="99999" class="<%= !animated ? 'no-animations' : '' %>">
|
||||||
+ (!!base.header)*80 + (user.isHireable)*16
|
|
||||||
+ (!!base.metadata)*38
|
|
||||||
+ ((!!base.activity)||(!!base.community))*128
|
|
||||||
+ (!!base.repositories)*108
|
|
||||||
+ ((!!base.repositories)*((!!plugins.traffic)||(!!plugins.lines)))*16
|
|
||||||
+ (!!plugins.followup)*68
|
|
||||||
+ (!!plugins.pagespeed)*126 + (plugins.pagespeed?.detailed ?? 0)*6*20 + (!!plugins.pagespeed?.screenshot)*330
|
|
||||||
+ (!!plugins.habits)*28 + (!!plugins.habits?.facts)*58 + (!!plugins.habits?.charts)*226
|
|
||||||
+ (!!plugins.languages)*96
|
|
||||||
+ (!!plugins.music)*64 + (plugins.music?.tracks?.length ? 14+Math.max(0, plugins.music.tracks.length-1)*36 : 0)
|
|
||||||
+ (!!plugins.posts)*64 + (plugins.posts?.list?.length ?? 0)*40
|
|
||||||
+ (!!plugins.isocalendar)*192 + (plugins.isocalendar?.duration === 'full-year')*100
|
|
||||||
+ (!!plugins.gists)*68
|
|
||||||
+ (!!plugins.topics)*160
|
|
||||||
+ (!!plugins.projects)*22 + (plugins.projects?.list?.length ?? 0)*60 + (!!plugins.projects?.error)*22
|
|
||||||
+ (!!plugins.tweets)*64 + (plugins.tweets?.list?.length ?? 0)*90
|
|
||||||
+ Math.max(0, (((!!base.metadata)+(!!base.header)+((!!base.activity)||(!!base.community))+(!!base.repositories)+((!!plugins.habits))+(!!plugins.pagespeed)+(!!plugins.languages)+(!!plugins.music)+(!!plugins.posts)+(!!plugins.isocalendar)+(!!plugins.gists)+(!!plugins.topics)+(!!plugins.projects))-1))*4
|
|
||||||
%>">
|
|
||||||
|
|
||||||
<defs><style><%= fonts %></style></defs>
|
<defs><style><%= fonts %></style></defs>
|
||||||
|
|
||||||
@@ -802,6 +784,7 @@
|
|||||||
</footer>
|
</footer>
|
||||||
<% } %>
|
<% } %>
|
||||||
|
|
||||||
|
<div id="metrics-end"></div>
|
||||||
</div>
|
</div>
|
||||||
</foreignObject>
|
</foreignObject>
|
||||||
</svg>
|
</svg>
|
||||||
|
Before Width: | Height: | Size: 75 KiB After Width: | Height: | Size: 74 KiB |
@@ -422,3 +422,17 @@
|
|||||||
--color-calendar-graph-day-L2-border: rgba(27,31,35,0.06);
|
--color-calendar-graph-day-L2-border: rgba(27,31,35,0.06);
|
||||||
--color-calendar-graph-day-L1-border: rgba(27,31,35,0.06);
|
--color-calendar-graph-day-L1-border: rgba(27,31,35,0.06);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* End delimiter */
|
||||||
|
#metrics-end {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.no-animations * {
|
||||||
|
transition-delay: 0s !important;
|
||||||
|
transition-duration: 0s !important;
|
||||||
|
animation-delay: -0.0001s !important;
|
||||||
|
animation-duration: 0s !important;
|
||||||
|
animation-play-state: paused !important;
|
||||||
|
caret-color: transparent !important;
|
||||||
|
}
|
||||||
@@ -18,6 +18,12 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//Animations
|
||||||
|
if ("config.animations" in q) {
|
||||||
|
data.animated = q["config.animations"]
|
||||||
|
console.debug(`metrics/compute/${login} > animations ${data.animated ? "enabled" : "disabled"}`)
|
||||||
|
}
|
||||||
|
|
||||||
//Plugins
|
//Plugins
|
||||||
for (const name of Object.keys(imports.plugins)) {
|
for (const name of Object.keys(imports.plugins)) {
|
||||||
if (!plugins[name].enabled)
|
if (!plugins[name].enabled)
|
||||||
|
|||||||
@@ -1,11 +1,4 @@
|
|||||||
<svg xmlns="http://www.w3.org/2000/svg" width="480" height="<%= 0
|
<svg xmlns="http://www.w3.org/2000/svg" width="480" height="99999" class="<%= !animated ? 'no-animations' : '' %>">
|
||||||
+ (!!base.header)*42
|
|
||||||
+ (!!plugins.traffic)*18
|
|
||||||
+ (!!plugins.followup)*68
|
|
||||||
+ (!!base.metadata)*28
|
|
||||||
+ (!!plugins.projects)*22 + (plugins.projects?.list?.length ?? 0)*60 + (!!plugins.projects?.error)*22
|
|
||||||
+ Math.max(0, ((!!base.header)+(!!base.metadata)+(!!plugins.followup)+(!!plugins.projects))-1)*4
|
|
||||||
%>">
|
|
||||||
|
|
||||||
<defs><style><%= fonts %></style></defs>
|
<defs><style><%= fonts %></style></defs>
|
||||||
|
|
||||||
@@ -216,6 +209,7 @@
|
|||||||
</footer>
|
</footer>
|
||||||
<% } %>
|
<% } %>
|
||||||
|
|
||||||
|
<div id="metrics-end"></div>
|
||||||
</div>
|
</div>
|
||||||
</foreignObject>
|
</foreignObject>
|
||||||
</svg>
|
</svg>
|
||||||
|
Before Width: | Height: | Size: 18 KiB After Width: | Height: | Size: 18 KiB |
@@ -1,17 +1,4 @@
|
|||||||
<svg xmlns="http://www.w3.org/2000/svg" width="480" height="<%= 48
|
<svg xmlns="http://www.w3.org/2000/svg" width="480" height="99999" class="<%= !animated ? 'no-animations' : '' %>">
|
||||||
+ (!!base.header)*62
|
|
||||||
+ (!!base.metadata)*108
|
|
||||||
+ (!!base.activity)*108
|
|
||||||
+ (!!base.community)*94
|
|
||||||
+ (!!base.repositories)*142
|
|
||||||
+ ((!!base.repositories)*(!!plugins.traffic))*18
|
|
||||||
+ ((!!base.repositories)*(!!plugins.followup))*102
|
|
||||||
+ ((!!base.repositories)*(!!plugins.lines))*34
|
|
||||||
+ (!!plugins.pagespeed)*110 + (plugins.pagespeed?.detailed ?? 0)*6*16
|
|
||||||
+ (!!plugins.languages)*124
|
|
||||||
+ (!!plugins.gists)*58
|
|
||||||
+ Math.max(0, (((!!base.metadata)+(!!base.header)+((!!base.activity)||(!!base.community))+(!!base.repositories)+(!!plugins.pagespeed)+(!!plugins.languages)+(!!plugins.gists))-1))*20
|
|
||||||
%>">
|
|
||||||
<%
|
<%
|
||||||
meta.$ = `<span class="ps1-path">${`${user.login}`.toLocaleLowerCase()}@metrics</span>:<span class="ps1-location">~</span>${computed.token.scopes.includes("repo") ? "#" : "$"}`
|
meta.$ = `<span class="ps1-path">${`${user.login}`.toLocaleLowerCase()}@metrics</span>:<span class="ps1-location">~</span>${computed.token.scopes.includes("repo") ? "#" : "$"}`
|
||||||
meta.animations = !meta.placeholder ? {stdin:.16, stdout:.28, length:(2+Object.keys(base).length+Object.keys(plugins).length)} : {stdin:0, stdout:0, length:0}
|
meta.animations = !meta.placeholder ? {stdin:.16, stdout:.28, length:(2+Object.keys(base).length+Object.keys(plugins).length)} : {stdin:0, stdout:0, length:0}
|
||||||
@@ -174,6 +161,7 @@ Total <%= plugins.gists.totalCount %> gist<%= s(plugins.gists.totalCount) %>
|
|||||||
<footer>Connection reset by <%= Math.floor(256*Math.random()) %>.<%= Math.floor(256*Math.random()) %>.<%= Math.floor(256*Math.random()) %>.<%= Math.floor(256*Math.random()) %></footer><%# -%>
|
<footer>Connection reset by <%= Math.floor(256*Math.random()) %>.<%= Math.floor(256*Math.random()) %>.<%= Math.floor(256*Math.random()) %>.<%= Math.floor(256*Math.random()) %></footer><%# -%>
|
||||||
<% } -%></pre>
|
<% } -%></pre>
|
||||||
|
|
||||||
|
<div id="metrics-end"></div>
|
||||||
</div>
|
</div>
|
||||||
</foreignObject>
|
</foreignObject>
|
||||||
</svg>
|
</svg>
|
||||||
|
|||||||
|
Before Width: | Height: | Size: 9.8 KiB After Width: | Height: | Size: 9.3 KiB |
@@ -56,6 +56,7 @@
|
|||||||
}
|
}
|
||||||
pre {
|
pre {
|
||||||
background: #42092B;
|
background: #42092B;
|
||||||
|
margin-top: 16px;
|
||||||
padding: 12px;
|
padding: 12px;
|
||||||
border-radius: 5px;
|
border-radius: 5px;
|
||||||
}
|
}
|
||||||
@@ -125,3 +126,17 @@
|
|||||||
--color-calendar-graph-day-L2-border: rgba(27,31,35,0.06);
|
--color-calendar-graph-day-L2-border: rgba(27,31,35,0.06);
|
||||||
--color-calendar-graph-day-L1-border: rgba(27,31,35,0.06);
|
--color-calendar-graph-day-L1-border: rgba(27,31,35,0.06);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* End delimiter */
|
||||||
|
#metrics-end {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.no-animations * {
|
||||||
|
transition-delay: 0s !important;
|
||||||
|
transition-duration: 0s !important;
|
||||||
|
animation-delay: -0.0001s !important;
|
||||||
|
animation-duration: 0s !important;
|
||||||
|
animation-play-state: paused !important;
|
||||||
|
caret-color: transparent !important;
|
||||||
|
}
|
||||||
@@ -31,37 +31,66 @@
|
|||||||
//Web instance
|
//Web instance
|
||||||
const web = {}
|
const web = {}
|
||||||
web.run = async (vars) => (await axios(`http://localhost:3000/lowlighter?${new url.URLSearchParams(Object.fromEntries(Object.entries(vars).map(([key, value]) => [key.replace(/^plugin_/, "").replace(/_/g, "."), value])))}`)).status === 200
|
web.run = async (vars) => (await axios(`http://localhost:3000/lowlighter?${new url.URLSearchParams(Object.fromEntries(Object.entries(vars).map(([key, value]) => [key.replace(/^plugin_/, "").replace(/_/g, "."), value])))}`)).status === 200
|
||||||
beforeAll(async () => await new Promise((solve, reject) => {
|
beforeAll(async done => {
|
||||||
|
await new Promise((solve, reject) => {
|
||||||
let stdout = ""
|
let stdout = ""
|
||||||
web.instance = processes.spawn("node", ["source/app/web/index.mjs"], {env:{...process.env, USE_MOCKED_DATA:true}})
|
web.instance = processes.spawn("node", ["source/app/web/index.mjs"], {env:{...process.env, USE_MOCKED_DATA:true, NO_SETTINGS:true}})
|
||||||
web.instance.stdout.on("data", data => (stdout += data, /Server ready !/.test(stdout) ? solve() : null))
|
web.instance.stdout.on("data", data => (stdout += data, /Server ready !/.test(stdout) ? solve() : null))
|
||||||
web.instance.stderr.on("data", data => console.error(`${data}`))
|
web.instance.stderr.on("data", data => console.error(`${data}`))
|
||||||
}))
|
})
|
||||||
afterAll(async () => await web.instance.kill())
|
done()
|
||||||
|
})
|
||||||
|
afterAll(async done => {
|
||||||
|
await web.instance.kill("SIGKILL")
|
||||||
|
done()
|
||||||
|
})
|
||||||
|
|
||||||
//Test cases
|
//Test cases
|
||||||
const tests = [
|
const tests = [
|
||||||
["Base (header)", {
|
["Base (header)", {
|
||||||
base:"header"
|
base:"header",
|
||||||
|
base_header:true,
|
||||||
}],
|
}],
|
||||||
["Base (activity", {
|
["Base (activity", {
|
||||||
base:"activity"
|
base:"activity",
|
||||||
|
base_activity:true,
|
||||||
}],
|
}],
|
||||||
["Base (community)", {
|
["Base (community)", {
|
||||||
base:"community"
|
base:"community",
|
||||||
|
base_community:true,
|
||||||
}],
|
}],
|
||||||
["Base (repositories)", {
|
["Base (repositories)", {
|
||||||
base:"repositories"
|
base:"repositories",
|
||||||
|
base_repositories:true,
|
||||||
}],
|
}],
|
||||||
["Base (metadata)", {
|
["Base (metadata)", {
|
||||||
base:"metadata"
|
base:"metadata",
|
||||||
|
base_metadata:true,
|
||||||
}],
|
}],
|
||||||
["Base (complete)", {
|
["Base (complete)", {
|
||||||
base:"header, activity, community, repositories, metadata"
|
base:"header, activity, community, repositories, metadata",
|
||||||
|
base_header:true,
|
||||||
|
base_activity:true,
|
||||||
|
base_community:true,
|
||||||
|
base_repositories:true,
|
||||||
|
base_metadata:true,
|
||||||
|
}],
|
||||||
|
["Image output (jpeg)", {
|
||||||
|
config_output:"jpeg",
|
||||||
|
}],
|
||||||
|
["Image output (png)", {
|
||||||
|
config_output:"png",
|
||||||
|
}],
|
||||||
|
["Disable animations", {
|
||||||
|
config_animations:"no",
|
||||||
}],
|
}],
|
||||||
["PageSpeed plugin (default)", {
|
["PageSpeed plugin (default)", {
|
||||||
plugin_pagespeed:true,
|
plugin_pagespeed:true,
|
||||||
}, {skip:["repository"]}],
|
}, {skip:["repository"]}],
|
||||||
|
["PageSpeed plugin (different url)", {
|
||||||
|
plugin_pagespeed:true,
|
||||||
|
plugin_pagespeed_url:"github.com",
|
||||||
|
}, {skip:["repository"]}],
|
||||||
["PageSpeed plugin (detailed)", {
|
["PageSpeed plugin (detailed)", {
|
||||||
plugin_pagespeed:true,
|
plugin_pagespeed:true,
|
||||||
plugin_pagespeed_detailed:true,
|
plugin_pagespeed_detailed:true,
|
||||||
@@ -179,6 +208,10 @@
|
|||||||
["Tweets plugin (default)", {
|
["Tweets plugin (default)", {
|
||||||
plugin_tweets:true,
|
plugin_tweets:true,
|
||||||
}, {skip:["terminal", "repository"]}],
|
}, {skip:["terminal", "repository"]}],
|
||||||
|
["Tweets plugin (different user)", {
|
||||||
|
plugin_tweets:true,
|
||||||
|
plugin_tweets_user:"twitterdev",
|
||||||
|
}, {skip:["terminal", "repository"]}],
|
||||||
["Posts plugin (dev.to)", {
|
["Posts plugin (dev.to)", {
|
||||||
user:"lowlighter",
|
user:"lowlighter",
|
||||||
plugin_posts:true,
|
plugin_posts:true,
|
||||||
|
|||||||
Reference in New Issue
Block a user