├── .gitgnore ├── extension-source-chrome ├── styles │ └── styles.css ├── images │ ├── icon-128.png │ ├── icon-16.png │ ├── icon-32.png │ ├── icon-48.png │ └── icon-512.png ├── popup.html ├── scripts │ ├── background.js │ └── content.js └── manifest.json ├── extension.crx ├── images ├── github-org-issues.png ├── github-org-issues-link.png ├── github-org-issues-1280x800.png ├── github-org-issues-1400x560.png ├── github-org-issues-440x280.png ├── github-org-issues-640x400.png └── github-org-issues-920x680.png ├── extension-source-firefox ├── images │ ├── icon-16.png │ ├── icon-32.png │ ├── icon-48.png │ ├── icon-128.png │ └── icon-512.png ├── manifest.json └── scripts │ └── content.js ├── README.md └── LICENSE.md /.gitgnore: -------------------------------------------------------------------------------- 1 | extension.pem -------------------------------------------------------------------------------- /extension-source-chrome/styles/styles.css: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /extension.crx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stefanbohacek/github-org-issues-link/HEAD/extension.crx -------------------------------------------------------------------------------- /images/github-org-issues.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stefanbohacek/github-org-issues-link/HEAD/images/github-org-issues.png -------------------------------------------------------------------------------- /images/github-org-issues-link.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stefanbohacek/github-org-issues-link/HEAD/images/github-org-issues-link.png -------------------------------------------------------------------------------- /images/github-org-issues-1280x800.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stefanbohacek/github-org-issues-link/HEAD/images/github-org-issues-1280x800.png -------------------------------------------------------------------------------- /images/github-org-issues-1400x560.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stefanbohacek/github-org-issues-link/HEAD/images/github-org-issues-1400x560.png -------------------------------------------------------------------------------- /images/github-org-issues-440x280.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stefanbohacek/github-org-issues-link/HEAD/images/github-org-issues-440x280.png -------------------------------------------------------------------------------- /images/github-org-issues-640x400.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stefanbohacek/github-org-issues-link/HEAD/images/github-org-issues-640x400.png -------------------------------------------------------------------------------- /images/github-org-issues-920x680.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stefanbohacek/github-org-issues-link/HEAD/images/github-org-issues-920x680.png -------------------------------------------------------------------------------- /extension-source-chrome/images/icon-128.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stefanbohacek/github-org-issues-link/HEAD/extension-source-chrome/images/icon-128.png -------------------------------------------------------------------------------- /extension-source-chrome/images/icon-16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stefanbohacek/github-org-issues-link/HEAD/extension-source-chrome/images/icon-16.png -------------------------------------------------------------------------------- /extension-source-chrome/images/icon-32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stefanbohacek/github-org-issues-link/HEAD/extension-source-chrome/images/icon-32.png -------------------------------------------------------------------------------- /extension-source-chrome/images/icon-48.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stefanbohacek/github-org-issues-link/HEAD/extension-source-chrome/images/icon-48.png -------------------------------------------------------------------------------- /extension-source-chrome/images/icon-512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stefanbohacek/github-org-issues-link/HEAD/extension-source-chrome/images/icon-512.png -------------------------------------------------------------------------------- /extension-source-firefox/images/icon-16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stefanbohacek/github-org-issues-link/HEAD/extension-source-firefox/images/icon-16.png -------------------------------------------------------------------------------- /extension-source-firefox/images/icon-32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stefanbohacek/github-org-issues-link/HEAD/extension-source-firefox/images/icon-32.png -------------------------------------------------------------------------------- /extension-source-firefox/images/icon-48.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stefanbohacek/github-org-issues-link/HEAD/extension-source-firefox/images/icon-48.png -------------------------------------------------------------------------------- /extension-source-firefox/images/icon-128.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stefanbohacek/github-org-issues-link/HEAD/extension-source-firefox/images/icon-128.png -------------------------------------------------------------------------------- /extension-source-firefox/images/icon-512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stefanbohacek/github-org-issues-link/HEAD/extension-source-firefox/images/icon-512.png -------------------------------------------------------------------------------- /extension-source-chrome/popup.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 |

GitHub Organization Issues Link

5 |

By @fourtonfish

6 |

Image credit: Emoji One

7 | 8 | 9 | -------------------------------------------------------------------------------- /extension-source-chrome/scripts/background.js: -------------------------------------------------------------------------------- 1 | chrome.runtime.onInstalled.addListener(function() { 2 | chrome.declarativeContent.onPageChanged.removeRules(undefined, function() { 3 | chrome.declarativeContent.onPageChanged.addRules([{ 4 | conditions: [new chrome.declarativeContent.PageStateMatcher({ 5 | pageUrl: {hostEquals: 'github.com'}, 6 | }) 7 | ], 8 | actions: [new chrome.declarativeContent.ShowPageAction()] 9 | }]); 10 | }); 11 | }); 12 | -------------------------------------------------------------------------------- /extension-source-firefox/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Github Organization Issues Link", 3 | "description" : "Link to all issues across an organization's repos.", 4 | "homepage_url": "https://fourtonfish.com/project/github-organization-issues-link-chrome-extension/", 5 | "version": "1.4.1", 6 | "manifest_version": 2, 7 | "permissions": [ 8 | "*://*.github.com/*", 9 | "webRequest" 10 | ], 11 | "content_scripts": [{ 12 | "js": ["scripts/content.js"], 13 | "matches": ["*://*.github.com/*"] 14 | }], 15 | "icons": { 16 | "16": "images/icon-16.png", 17 | "32": "images/icon-32.png", 18 | "48": "images/icon-48.png", 19 | "128": "images/icon-128.png" 20 | } 21 | } -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # GitHub Organization Issues Link 2 | 3 | A browser extension that adds an *Issues* tab that lets you browse all issues across a GitHub organization's repos. 4 | 5 | ![An example of an Issues link added to a GitHub organization's page](images/github-org-issues.png) 6 | 7 | ![Search page that filters all open issues across all organization's repos](images/github-org-issues-link.png) 8 | 9 | - [**Add to Firefox**](https://addons.mozilla.org/en-US/firefox/addon/github-org-issues-link/) 10 | - [**Add to Chrome**](https://chrome.google.com/webstore/detail/github-organization-issue/apjhcnanjlebginfefonhmnammmmplma) 11 | 12 | ## Attributions 13 | 14 | - Images for the extension icon: [Emoji One](https://www.emojione.com/) 15 | -------------------------------------------------------------------------------- /extension-source-chrome/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Github Organization Issues Link", 3 | "description" : "Link to all issues across an organization's repos.", 4 | "permissions": ["declarativeContent"], 5 | "version": "1.4.2", 6 | "manifest_version": 2, 7 | "content_scripts": [{ 8 | "css": ["styles/styles.css"], 9 | "js": ["scripts/content.js"], 10 | "matches": ["https://github.com/*"] 11 | }], 12 | "page_action": { 13 | "default_popup": "popup.html", 14 | "default_icon": { 15 | "16": "images/icon-16.png", 16 | "32": "images/icon-32.png", 17 | "48": "images/icon-48.png", 18 | "128": "images/icon-128.png" 19 | } 20 | }, 21 | "background": { 22 | "scripts": ["scripts/background.js"], 23 | "persistent": false 24 | }, 25 | "icons": { 26 | "16": "images/icon-16.png", 27 | "32": "images/icon-32.png", 28 | "48": "images/icon-48.png", 29 | "128": "images/icon-128.png" 30 | } 31 | } -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2019 Stefan Bohacek 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /extension-source-chrome/scripts/content.js: -------------------------------------------------------------------------------- 1 | const ready = ( fn ) => { 2 | if ( document.attachEvent ? document.readyState === 'complete' : document.readyState !== 'loading' ){ 3 | fn(); 4 | } else { 5 | document.addEventListener( 'DOMContentLoaded', fn ); 6 | } 7 | } 8 | 9 | ready( () => { 10 | const addLink = ( options ) => { 11 | let linkWrapper = document.createElement( 'li' ); 12 | linkWrapper.classList.add( 'd-flex' ); 13 | linkWrapper.classList.add( 'js-responsive-underlinenav-item' ); 14 | 15 | let link = document.createElement( 'a' ); 16 | 17 | link.setAttribute( 'href', options.linkURL ); 18 | link.innerHTML = options.linkHTML; 19 | link.classList.add( 'UnderlineNav-item' ); 20 | linkWrapper.appendChild( link ); 21 | orgnav.querySelector('ul').appendChild( linkWrapper ); 22 | 23 | if (options.dataURL){ 24 | fetch( options.dataURL ) 25 | .then( response => response.json() ) 26 | .then( data => { 27 | if ( data && data[options.dataValue] ){ 28 | document.getElementById( options.dataID ).innerHTML = formatNumber( data[options.dataValue] ); 29 | } 30 | } ).catch( ( err ) => { 31 | console.log( err.message ); 32 | } ); 33 | } 34 | } 35 | 36 | const formatNumber = (number, decimals, dec_point, thousands_sep) => { 37 | /* Source: 38 | https://stackoverflow.com/questions/2901102/how-to-print-a-number-with-commas-as-thousands-separators-in-javascript/2901136#2901136 39 | */ 40 | var n = !isFinite(+number) ? 0 : +number, 41 | prec = !isFinite(+decimals) ? 0 : Math.abs(decimals), 42 | sep = (typeof thousands_sep === 'undefined') ? ',' : thousands_sep, 43 | dec = (typeof dec_point === 'undefined') ? '.' : dec_point, 44 | toFixedFix = (n, prec) => { 45 | // Fix for IE parseFloat(0.55).toFixed(0) = 0; 46 | var k = Math.pow(10, prec); 47 | return Math.round(n * k) / k; 48 | }, 49 | s = (prec ? toFixedFix(n, prec) : Math.round(n)).toString().split('.'); 50 | if (s[0].length > 3) { 51 | s[0] = s[0].replace(/\B(?=(?:\d{3})+(?!\d))/g, sep); 52 | } 53 | if ((s[1] || '').length < prec) { 54 | s[1] = s[1] || ''; 55 | s[1] += new Array(prec - s[1].length + 1).join('0'); 56 | } 57 | return s.join(dec); 58 | } 59 | 60 | const getMeta = ( metaName ) => { 61 | /* Source: 62 | https://stackoverflow.com/questions/7524585/how-do-i-get-the-information-from-a-meta-tag-with-javascript/7524621#7524621 */ 63 | const metas = document.getElementsByTagName('meta'); 64 | 65 | for ( let i = 0; i < metas.length; i++ ) { 66 | if ( metas[i].getAttribute( 'property' ) === metaName || metas[i].getAttribute( 'name' ) === metaName ) { 67 | return metas[i].getAttribute( 'content' ); 68 | } 69 | } 70 | return ''; 71 | } 72 | 73 | let orgnav = document.getElementsByClassName( 'js-profile-tab-count-container' ); 74 | 75 | if ( orgnav && orgnav.length > 0 ){ 76 | orgnav = orgnav[0]; 77 | const orgName = getMeta( 'profile:username' ); 78 | 79 | if ( orgName ){ 80 | addLink({ 81 | linkURL: `https://github.com/search?q=org%3A${ orgName }+is%3Aissue&state=open&type=Issues`, 82 | linkHTML: `Issues `, 83 | dataURL: `https://api.github.com/search/issues?q=org:${ orgName }+state:open&per_page=100&sort=created&order=asc`, 84 | dataID: 'org-issues-counter', 85 | dataValue: 'total_count' 86 | }); 87 | addLink({ 88 | linkURL: `https://github.com/search?q=user%3A${ orgName }+label%3A%22help+wanted%22&type=Issues&ref=advsearch&state=open&type=Issues`, 89 | linkHTML: `Help wanted` 90 | }); 91 | } 92 | } 93 | } ); 94 | -------------------------------------------------------------------------------- /extension-source-firefox/scripts/content.js: -------------------------------------------------------------------------------- 1 | const ready = ( fn ) => { 2 | if ( document.attachEvent ? document.readyState === 'complete' : document.readyState !== 'loading' ){ 3 | fn(); 4 | } else { 5 | document.addEventListener( 'DOMContentLoaded', fn ); 6 | } 7 | } 8 | 9 | ready( () => { 10 | const addLink = ( options ) => { 11 | let linkWrapper = document.createElement( 'li' ); 12 | linkWrapper.classList.add( 'd-flex' ); 13 | linkWrapper.classList.add( 'js-responsive-underlinenav-item' ); 14 | 15 | let link = document.createElement( 'a' ); 16 | 17 | link.setAttribute( 'href', options.linkURL ); 18 | link.innerHTML = options.linkHTML; 19 | link.classList.add( 'UnderlineNav-item' ); 20 | linkWrapper.appendChild( link ); 21 | orgnav.querySelector('ul').appendChild( linkWrapper ); 22 | 23 | if (options.dataURL){ 24 | fetch( options.dataURL ) 25 | .then( response => response.json() ) 26 | .then( data => { 27 | if ( data && data[options.dataValue] ){ 28 | document.getElementById( options.dataID ).innerHTML = formatNumber( data[options.dataValue] ); 29 | } 30 | } ).catch( ( err ) => { 31 | console.log( err.message ); 32 | } ); 33 | } 34 | } 35 | 36 | const formatNumber = (number, decimals, dec_point, thousands_sep) => { 37 | /* Source: 38 | https://stackoverflow.com/questions/2901102/how-to-print-a-number-with-commas-as-thousands-separators-in-javascript/2901136#2901136 39 | */ 40 | var n = !isFinite(+number) ? 0 : +number, 41 | prec = !isFinite(+decimals) ? 0 : Math.abs(decimals), 42 | sep = (typeof thousands_sep === 'undefined') ? ',' : thousands_sep, 43 | dec = (typeof dec_point === 'undefined') ? '.' : dec_point, 44 | toFixedFix = (n, prec) => { 45 | // Fix for IE parseFloat(0.55).toFixed(0) = 0; 46 | var k = Math.pow(10, prec); 47 | return Math.round(n * k) / k; 48 | }, 49 | s = (prec ? toFixedFix(n, prec) : Math.round(n)).toString().split('.'); 50 | if (s[0].length > 3) { 51 | s[0] = s[0].replace(/\B(?=(?:\d{3})+(?!\d))/g, sep); 52 | } 53 | if ((s[1] || '').length < prec) { 54 | s[1] = s[1] || ''; 55 | s[1] += new Array(prec - s[1].length + 1).join('0'); 56 | } 57 | return s.join(dec); 58 | } 59 | 60 | const getMeta = ( metaName ) => { 61 | /* Source: 62 | https://stackoverflow.com/questions/7524585/how-do-i-get-the-information-from-a-meta-tag-with-javascript/7524621#7524621 */ 63 | const metas = document.getElementsByTagName('meta'); 64 | 65 | for ( let i = 0; i < metas.length; i++ ) { 66 | if ( metas[i].getAttribute( 'property' ) === metaName || metas[i].getAttribute( 'name' ) === metaName ) { 67 | return metas[i].getAttribute( 'content' ); 68 | } 69 | } 70 | return ''; 71 | } 72 | 73 | let orgnav = document.getElementsByClassName( 'js-profile-tab-count-container' ); 74 | 75 | if ( orgnav && orgnav.length > 0 ){ 76 | orgnav = orgnav[0]; 77 | const orgName = getMeta( 'profile:username' ); 78 | 79 | if ( orgName ){ 80 | addLink({ 81 | linkURL: `https://github.com/search?q=org%3A${ orgName }+is%3Aissue&state=open&type=Issues`, 82 | linkHTML: `Issues `, 83 | dataURL: `https://api.github.com/search/issues?q=org:${ orgName }+state:open&per_page=100&sort=created&order=asc`, 84 | dataID: 'org-issues-counter', 85 | dataValue: 'total_count' 86 | }); 87 | addLink({ 88 | linkURL: `https://github.com/search?q=user%3A${ orgName }+label%3A%22help+wanted%22&type=Issues&ref=advsearch&state=open&type=Issues`, 89 | linkHTML: `Help wanted` 90 | }); 91 | } 92 | } 93 | } ); 94 | --------------------------------------------------------------------------------