// ==UserScript== // @name GitHub Issue Counts // @version 3.0.20 // @description A userscript that adds a repo issues count to the repository tab & organization page (https://github.com/:user) // @license MIT // @author Rob Garrison // @namespace https://github.com/Mottie // @match https://github.com/* // @run-at document-idle // @grant GM_addStyle // @grant GM_xmlhttpRequest // @connect api.github.com // @require https://greasyfork.org/scripts/28721-mutations/code/mutations.js?version=1108163 // @icon https://github.githubassets.com/pinned-octocat.svg // @updateURL https://raw.githubusercontent.com/Mottie/Github-userscripts/master/github-issue-counts.user.js // @downloadURL https://raw.githubusercontent.com/Mottie/Github-userscripts/master/github-issue-counts.user.js // @supportURL https://github.com/Mottie/GitHub-userscripts/issues // ==/UserScript== (() => { "use strict"; // issue count = get all repos from user => api v3 // https://api.github.com/users/:user/repos // then look for "open_issues_count" in the named repos const api = "https://api.github.com/users", // bug icon icon = ``, repoSelectors = ` #user-repositories-list li, #org-repositories li, ol.pinned-repos-list li `; // add bug image styling GM_addStyle(` .repo-list-stats a.issues svg { position: relative; top: 2px; fill: #888; } .repo-list-stats a.issues:hover svg { fill: #4078C0; } `); /* * Org repos * container = div#org-repositories > div > div.org-repos.repo-list > li * User repos * container = div#user-repositories-list > div.js-repo-list > li * Common org/user * repo url = container h3 a (first a) * issue link location = container div[3] a[last]:after * fork link HTML - both user/org (Dec 2016) * * :fork-count * * * Pinned repos * container = ol.pinned-repos-list li.pinned-repo-item * repo url = container span span a (first a) * issue link location = container > span.pinned-repo-item-content p[last] a[last]:after * fork link HTML * * :fork-count * */ function addLinks(data, repos) { repos.forEach(repo => { let wrapper, el, html, setClass; const url = ($("a", repo).getAttribute("href") || "").slice(1), result = url && data.find(item => { return item.full_name === url; }); // pinned if (repo.classList.contains("pinned-repo-item")) { el = $$(".pinned-repo-item-content p:last-child", repo); setClass = "muted-link ghic2-issue-link"; } else { // user/org list = last div in repo list contains links wrapper = $$("div", repo); el = wrapper && $$("a", wrapper[wrapper.length - 1]); setClass = "muted-link tooltipped tooltipped-s mr-3 ghic2-issue-link"; } if (el) { if (result && typeof result.open_issues_count === "number") { html = ` ${icon} ${result.open_issues_count} `; // target the last "a" el = el[el.length - 1]; // add after last link, sometimes there is no fork if (el) { if (el.tagName === "P") { wrapper = document.createElement("span"); wrapper.className = "ghic-link pinned-repo-meta"; el.appendChild(wrapper); el.querySelector(".ghic-link").innerHTML = html; } else { el.insertAdjacentHTML("afterend", html); } } } } }); } function addIssues() { let user, url, repos = $$(repoSelectors); if ( // look for user overview, user repositories & organization repo page repos.length && // and not already applied !$$(".ghic2-issue-link").length ) { // no issue count for non-public & forks repos = repos.filter(repo => { let list = repo.classList; return list.contains("public") && !list.contains("fork"); }); if (repos.length) { url = $("a", repos[ 0 ]).getAttribute("href"); user = (url || "").match(/^\/[^/]+/); if (user && user.length) { GM_xmlhttpRequest({ method : "GET", url : api + user[0] + "/repos", onload : response => { const data = JSON.parse(response.responseText || "null"); if (data) { addLinks(data, repos); } } }); } } } } function $(str, el) { return (el || document).querySelector(str); } function $$(str, el) { return Array.from((el || document).querySelectorAll(str)); } document.addEventListener("ghmo:container", addIssues); addIssues(); })();
Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.
Alternative Proxies: