Skip to content

Instantly share code, notes, and snippets.

@jtwalters
Last active April 21, 2017 17:30
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save jtwalters/51cc2ed5923f6e53fd34927809c9acff to your computer and use it in GitHub Desktop.
Save jtwalters/51cc2ed5923f6e53fd34927809c9acff to your computer and use it in GitHub Desktop.
Better Filters for GitHub — Provides filters for GitHub Projects.

Better Filters for GitHub was written to help a large Project board more manageable, by toggling the label display, and filtering down to issues tagged with a certain label or assignee.

It looks like this:

Install

// ==UserScript==
// @name Better Filters for GitHub
// @namespace http://joelwalters.com/
// @version 1.0
// @description Provides filters for GitHub Projects.
// @author Joel Walters
// @match https://github.com/*
// @grant GM_addStyle
// @require http://code.jquery.com/jquery-3.2.1.slim.min.js
// @require https://cdnjs.cloudflare.com/ajax/libs/underscore.js/1.8.3/underscore-min.js
// ==/UserScript==
(function ($) {
var projects = function () {
'use strict';
// jshint multistr:true
var $toggleLabels = $('<div><input type="checkbox" id="ghtToggleLabels" name="ghtToggleLabels"> <label for="ghtToggleLabels">Show Labels</label></div>');
var $filterLabel = $('<select class="ght-filter"><option value="">- Filter by Label -</option></select>');
var $filterAssignee = $('<select class="ght-filter"><option value="">- Filter by Assignee -</option></select>');
var $filterClear = $('<a href="#">&times; clear filters</a>');
var $controls = $('<div class="ght-controls"></div>');
var counts = {};
var values = {};
var cardCount;
var prevCardCount;
var intervalTimeout;
var checkCount = 0;
var options = JSON.parse(localStorage.getItem('ghtOptions')) || {};
_.defaults(options, {
showLabels: false,
label: '',
assignee: ''
});
function setInputsFromOptions() {
$filterLabel.val(options.label);
$filterAssignee.val(options.assignee);
$toggleLabels.find('input').prop('checked', options.showLabels);
}
function saveOptions() {
localStorage.setItem('ghtOptions', JSON.stringify(options));
}
function applyAndSaveOptions() {
var filters = {};
$('.project-columns .labels').toggleClass('ght-hidden', !options.showLabels);
$('.project-columns .issue-card').each(function () {
var showAllLabels = options.label === '',
showAllAssignees = options.assignee === '';
filters.label = showAllLabels || $(this).find('.issue-card-label').filter(function () {
return this.innerText === options.label;
}).length > 0;
filters.assignee = showAllAssignees || $(this).find('.avatar-stack .avatar').filter(function () {
return this.alt === options.assignee;
}).length > 0;
$(this).toggleClass('ght-hidden', !_.every(filters, function (isMatch) {
return isMatch;
}));
});
saveOptions();
}
GM_addStyle('.ght-controls { display: flex; }');
GM_addStyle('.ght-item { flex: 0 1 auto; margin: .5em 1em; }');
GM_addStyle('.ght-hidden { display: none !important; }');
$filterClear.on('click', function () {
$filterLabel.val('');
options.labels = '';
$filterAssignee.val('');
options.assignee = '';
applyAndSaveOptions();
});
$toggleLabels.find('input').on('change', function () {
options.showLabels = this.checked;
applyAndSaveOptions();
});
$filterAssignee.on('change', function () {
options.assignee = this.value;
applyAndSaveOptions();
});
$filterLabel.on('change', function () {
options.label = this.value;
applyAndSaveOptions();
});
// Check for async loaded cards.
intervalTimeout = setInterval(function checkLabels() {
cardCount = $('.project-columns .issue-card').length;
checkCount++;
if (checkCount > 5) {
clearInterval(intervalTimeout);
}
// Get all assignees.
values.assignees = $('.project-columns .avatar-stack .avatar').map(function () {
return this.alt;
});
// Create a lookup for count
counts.assignees = _.countBy(values.assignees);
values.assignees = _.uniq(values.assignees.sort());
// Get all labels.
values.labels = $('.project-columns .issue-card-label').map(function () {
return this.innerText;
});
// Create a lookup table for count (occurrences).
counts.labels = _.countBy(values.labels);
values.labels = _.uniq(values.labels.sort());
// Count changed, update the values.
if (cardCount !== prevCardCount) {
$filterLabel.find('option').slice(1).remove();
_.each(values.labels, function (label) {
$filterLabel.append('<option value="' + label + '">' + label + ' (' + counts.labels[label] + ')</option>');
});
$filterAssignee.find('option').slice(1).remove();
_.each(values.assignees, function (assignee) {
$filterAssignee.append('<option value="' + assignee + '">' + assignee + ' (' + counts.assignees[assignee] + ')</option>');
});
setInputsFromOptions();
applyAndSaveOptions();
}
prevCardCount = cardCount;
}, 1000);
$controls
.append($toggleLabels)
.append($filterLabel)
.append($filterAssignee)
.append($filterClear);
$controls.find('> *').wrap('<div class="ght-item">');
$('.project-columns').before($controls);
};
if ($('.project-columns').length) {
console.log('[GitHub Tweaks]', 'Activated projects tweaks');
projects();
}
})(jQuery);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment