Skip to content

Instantly share code, notes, and snippets.

@csvoss
Last active January 8, 2020 21:29
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 csvoss/b144ebd67fb3dc8f519722763d6a2cd8 to your computer and use it in GitHub Desktop.
Save csvoss/b144ebd67fb3dc8f519722763d6a2cd8 to your computer and use it in GitHub Desktop.
csvoss's GitHub Homepage++
// ==UserScript==
// @name GitHub Homepage ++
// @namespace
// @version 0.1
// @description Inject any PRs with reviews requested from me & any PRs waiting on me into the GitHub main page
// @author Chelsea Voss
// @match https://github.com/
// @grant none
// ==/UserScript==
(function() {
'use strict';
// Edit this variable!
const REPOS_YOU_CARE_ABOUT = [
"/YourOrg/yourrepo",
];
const username = document.getElementsByClassName("header-nav-current-user").item(0).getElementsByTagName("strong").item(0).innerHTML;
const dash = document.getElementById("dashboard");
const parser = new DOMParser();
function getDOMFromPath(path) {
const xmlhttp=new XMLHttpRequest();
xmlhttp.open("GET", path, false);
xmlhttp.send();
return parser.parseFromString(xmlhttp.responseText, "text/html");
}
function prependSpace(place) {
place.prepend(parser.parseFromString("<br/>", "text/html").firstChild);
}
function prependHeader(place, headerString, headerType) {
place.prepend(parser.parseFromString("<" + headerType + ">" + headerString + "</" + headerType + ">", "text/html").firstChild);
}
function prependSlot(place, id) {
place.prepend(parser.parseFromString("<div id=\"" + id + "\"></div>", "text/html").firstChild);
return document.getElementById(id);
}
function addGenericSearch(id, header, path) {
prependSpace(dash);
const slot = prependSlot(dash, id);
new Promise(function(resolve, reject) {
const searchPage = getDOMFromPath(path);
resolve(searchPage.getElementById("issue_search_results"));
}).then(function(searchResults) {
if (searchResults) {
slot.prepend(searchResults);
prependHeader(slot, header, "h3");
} else {
slot.prepend(header + ": none!");
}
});
}
function addPullRequestSearch(id, header, path, showStatus, showButton) {
prependSpace(dash);
const slot = prependSlot(dash, id);
function fetchList() {
const searchPage = getDOMFromPath(path);
return searchPage.getElementById("issue_search_results");
}
async function fillSlot() {
const searchResults = await fetchList();
if (searchResults) {
const pullRequests = searchResults.getElementsByClassName("issue-list-item");
for (let i=0; i<pullRequests.length; i+=0) {
const oldLength = pullRequests.length;
const searchResult = pullRequests.item(i);
if (showStatus || showButton) {
const subSlot = prependSlot(slot, id + i);
new Promise(function(resolve, reject) {
const pullRequestPath = searchResult.getElementsByTagName("h3").item(0).getElementsByTagName("a").item(0).getAttribute("href");
resolve(getDOMFromPath(pullRequestPath));
}).then(function(pullRequestPage) {
const changesSinceLastViewed = pullRequestPage.getElementsByClassName("discussion-item-changes-marker").item(0);
if (showButton) {
const reviewRequestButton = pullRequestPage.getElementsByClassName("issues-listing").item(0).getElementsByClassName("flash-warn").item(0);
subSlot.prepend(reviewRequestButton);
}
if (showStatus) {
const pullRequestStatus = pullRequestPage.getElementsByClassName("branch-action-body").item(0).getElementsByClassName("branch-action-item").item(0);
subSlot.prepend(pullRequestStatus);
}
if (changesSinceLastViewed !== null) {
subSlot.prepend(changesSinceLastViewed.getElementsByClassName("discussion-item-header").item(0));
}
});
}
slot.prepend(searchResult);
// i+=0 in the loop because weirdly, newLength goes down. I'm not sure why.
// Hedge against both of the possible behaviors while not infinite looping.
const newLength = pullRequests.length;
if (newLength === oldLength) {
i += 1;
}
}
prependHeader(slot, header, "h3");
} else {
slot.prepend(header + ": none!");
}
}
fillSlot();
}
function addRecentlyPushedBranches(id, header) {
prependSpace(dash);
let prependedHeader = false;
REPOS_YOU_CARE_ABOUT.forEach(function(path) {
const slot = prependSlot(dash, id + path);
const headerSlot = prependSlot(dash, id + "header");
function fetchList() {
const repositoryPage = getDOMFromPath(path + "/show_partial?partial=tree%2Frecently_touched_branches_list");
return repositoryPage.getElementsByClassName("RecentBranches").item(0);
}
async function fillSlot() {
const newBranchAlert = await fetchList();
if (newBranchAlert) {
slot.prepend(newBranchAlert);
if (!prependedHeader) {
prependSpace(slot);
prependHeader(headerSlot, header, "h3");
prependedHeader = true;
}
}
}
fillSlot();
});
}
prependSpace(dash);
prependSpace(dash);
addPullRequestSearch(
"prsopenednotreviewed",
"PRs you opened that aren't yet reviewed",
"/search?utf8=%E2%9C%93&q=is%3Aopen+is%3Apr+author%3A" + username + "+review%3Anone",
true, false
);
prependHeader(dash, "Waiting", "h1");
addGenericSearch(
"issuesassignedto",
"Issues you are assigned to",
"/search?utf8=%E2%9C%93&q=is%3Aopen+is%3Aissue+assignee%3A" + username + "+"
);
addPullRequestSearch(
"prswaitingonchanges",
"PRs waiting on your changes",
"/search?utf8=✓&q=is%3Aopen+is%3Apr+review%3Achanges-requested+author%3A" + username + "+",
true, false
);
addPullRequestSearch(
"prswaitingonship",
"PRs waiting for you to ship them",
"/search?utf8=✓&q=is%3Aopen+is%3Apr+review%3Aapproved+author%3A" + username + "+",
true, false
);
addPullRequestSearch(
"prswaitingonreview",
"PRs waiting on your review",
"/search?utf8=✓&q=is%3Aopen+is%3Apr+review-requested%3A" + username + "+",
false, true
);
addRecentlyPushedBranches(
"recentlypushedbranches",
"Your recently pushed branches"
);
prependHeader(dash, "Ready", "h1");
window.scrollTo(0, 0);
})();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment