diff --git a/source/app/metrics/utils.mjs b/source/app/metrics/utils.mjs index 83f41ec3..5cfc435d 100644 --- a/source/app/metrics/utils.mjs +++ b/source/app/metrics/utils.mjs @@ -36,6 +36,15 @@ return `${(n/v).toFixed(2).substr(0, 4).replace(/[.]0*$/, "")} ${u}B` return `${n} byte${n > 1 ? "s" : ""}` } + format.bytes = bytes + +/** Percentage formatter */ + export function percentage(n, {rescale = true} = {}) { + return `${(n*(rescale ? 100 : 1)).toFixed(2) + .replace(/(?<=[.])([1-9]*)(0+)$/, (m, a, b) => a) + .replace(/[.]$/, "")}%` + } + format.percentage = percentage /** Array shuffler */ export function shuffle(array) { diff --git a/source/plugins/base/index.mjs b/source/plugins/base/index.mjs index e42afaab..bc31138b 100644 --- a/source/plugins/base/index.mjs +++ b/source/plugins/base/index.mjs @@ -14,9 +14,9 @@ return (postprocess.skip({login, data}), {}) //Base parts (legacy handling for web instance) - const defaulted = ("base" in q) ? !!q.base : true + const defaulted = ("base" in q) ? legacy.converter(q.base) ?? true : true for (const part of conf.settings.plugins.base.parts) - data.base[part] = `base.${part}` in q ? !!q[ `base.${part}`] : defaulted + data.base[part] = `base.${part}` in q ? legacy.converter(q[ `base.${part}`]) : defaulted //Iterate through account types for (const account of ["user", "organization"]) { @@ -108,4 +108,16 @@ packages:{totalCount:0}, }) } + } + +//Legacy functions + const legacy = { + converter(value) { + if (/^(?:[Tt]rue|[Oo]n|[Yy]es|1)$/.test(value)) + return true + if (/^(?:[Ff]alse|[Oo]ff|[Nn]o|0)$/.test(value)) + return false + if (Number.isFinite(Number(value))) + return !!(Number(value)) + } } \ No newline at end of file diff --git a/source/plugins/languages/README.md b/source/plugins/languages/README.md index aca53e8f..a966a5d0 100644 --- a/source/plugins/languages/README.md +++ b/source/plugins/languages/README.md @@ -26,4 +26,5 @@ It is also possible to use a predefined set of colors from [colorsets.json](colo plugin_languages_ignored: html, css # List of languages to ignore plugin_languages_skipped: my-test-repo # List of repositories to skip plugin_languages_colors: "0:orange, javascript:#ff0000, ..." # Make most used languages orange and JavaScript red + plugin_languages_details: bytes-size, percentage # Additionally display total bytes size and percentage ``` diff --git a/source/plugins/languages/index.mjs b/source/plugins/languages/index.mjs index 95a0261c..d0503b23 100644 --- a/source/plugins/languages/index.mjs +++ b/source/plugins/languages/index.mjs @@ -7,7 +7,7 @@ return null //Load inputs - let {ignored, skipped, colors} = imports.metadata.plugins.languages.inputs({data, account, q}) + let {ignored, skipped, colors, details} = imports.metadata.plugins.languages.inputs({data, account, q}) //Custom colors const colorsets = JSON.parse(`${await imports.fs.readFile(`${imports.__module(import.meta.url)}/colorsets.json`)}`) @@ -18,7 +18,7 @@ //Iterate through user's repositories and retrieve languages data console.debug(`metrics/compute/${login}/plugins > languages > processing ${data.user.repositories.nodes.length} repositories`) - const languages = {colors:{}, total:0, stats:{}} + const languages = {details, colors:{}, total:0, stats:{}} for (const repository of data.user.repositories.nodes) { //Skip repository if asked if (skipped.includes(repository.name.toLocaleLowerCase())) { @@ -41,9 +41,10 @@ //Compute languages stats console.debug(`metrics/compute/${login}/plugins > languages > computing stats`) - Object.keys(languages.stats).map(name => languages.stats[name] /= languages.total) - languages.favorites = Object.entries(languages.stats).sort(([an, a], [bn, b]) => b - a).slice(0, 8).map(([name, value]) => ({name, value, color:languages.colors[name], x:0})) + languages.favorites = Object.entries(languages.stats).sort(([an, a], [bn, b]) => b - a).slice(0, 8).map(([name, value]) => ({name, value, size:value, color:languages.colors[name], x:0})) + const visible = {total:Object.values(languages.favorites).map(({size}) => size).reduce((a, b) => a + b, 0)} for (let i = 0; i < languages.favorites.length; i++) { + languages.favorites[i].value /= visible.total languages.favorites[i].x = (languages.favorites[i-1]?.x ?? 0) + (languages.favorites[i-1]?.value ?? 0) if ((colors[i])&&(!colors[languages.favorites[i].name.toLocaleLowerCase()])) languages.favorites[i].color = colors[i] diff --git a/source/plugins/languages/metadata.yml b/source/plugins/languages/metadata.yml index bbbe6b1b..192c980e 100644 --- a/source/plugins/languages/metadata.yml +++ b/source/plugins/languages/metadata.yml @@ -26,7 +26,7 @@ inputs: format: comma-separated default: "" - # Overrides + # Overrides default languages colors # Use `${n}:${color}` to change the color of the n-th most used language (e.g. "0:red" to make your most used language red) # Use `${language}:${color}` to change the color of named language (e.g. "javascript:red" to make JavaScript language red, language case is ignored) # Use a value from `colorsets.json` to use a predefined set of colors @@ -38,3 +38,13 @@ inputs: - comma-separated - /((?[0-9])|(?[-+a-z0-9#])):(?#?[-a-z0-9]+)/ default: github + + # Languages additional details + plugin_languages_details: + description: + type: array + format: comma-separated + values: + - bytes-size # Languages total size written in bytes + - percentage # Languages proportions in % + default: "" \ No newline at end of file diff --git a/source/templates/classic/partials/languages.ejs b/source/templates/classic/partials/languages.ejs index 244d41f1..742d21d2 100644 --- a/source/templates/classic/partials/languages.ejs +++ b/source/templates/classic/partials/languages.ejs @@ -1,6 +1,9 @@ <% if (plugins.languages) { %>
-

Most used languages

+

+ + Most used languages +

<% if (plugins.languages.error) { %>
@@ -18,14 +21,35 @@ <% } %> -
- <% for (const {name, value, color} of plugins.languages.favorites) { %> -
- - <%= name %> -
- <% } %> -
+ <% if (plugins.languages.details?.length) { %> +
+ <% for (const row of [0, 1]) { %> +
+ <% for (const {name, value, color, size} of plugins.languages.favorites.filter((_, i) => i%2 === row)) { %> +
+
+ + <%= name %> +
+ + <% if (plugins.languages.details.includes("bytes-size")) { %>
<%= f.bytes(size) %>
<% } %> + <% if (plugins.languages.details.includes("percentage")) { %>
<%= f.percentage(value) %>
<% } %> +
+
+ <% } %> +
+ <% } %> +
+ <% } else { %> +
+ <% for (const {name, value, color} of plugins.languages.favorites) { %> +
+ + <%= name %> +
+ <% } %> +
+ <% } %> <% } %>
<% } %> \ No newline at end of file diff --git a/source/templates/classic/style.css b/source/templates/classic/style.css index 64b2984d..93d4cb8e 100644 --- a/source/templates/classic/style.css +++ b/source/templates/classic/style.css @@ -114,9 +114,20 @@ flex-grow: 0; } - .field.language small { - margin-left: 4px; + .field.language.details { + display: flex; + justify-content: space-between; + } + + .field.language.details small { + display: flex; + justify-content: space-between; color: #666666; + text-align: right; + } + + .field.language.details > *, .field.language.details small > * { + flex: 1 1 0; } /* Labels */ diff --git a/tests/testscases.js b/tests/testscases.js index df6f3834..017e444c 100644 --- a/tests/testscases.js +++ b/tests/testscases.js @@ -105,11 +105,16 @@ plugin_languages:true, plugin_languages_colors:"complementary", }], + ["Language plugin (with details)", { + plugin_languages:true, + plugin_languages_details:"percentage", + }], ["Language plugin (complete)", { plugin_languages:true, plugin_languages_ignored:"html, css, dockerfile", plugin_languages_skipped:"metrics", plugin_languages_colors:"rainbow", + plugin_languages_details:"bytes-size, percentage", }], ["Follow-up plugin (default)", { plugin_followup:true,