Skip to content

Instantly share code, notes, and snippets.

@Nukem9
Created July 25, 2018 05:32
Show Gist options
  • Select an option

  • Save Nukem9/90e9d1233990a835dfce888c28e310c8 to your computer and use it in GitHub Desktop.

Select an option

Save Nukem9/90e9d1233990a835dfce888c28e310c8 to your computer and use it in GitHub Desktop.
// ==UserScript==
// @name ImproveGitHubDashboard
// @namespace http://tampermonkey.net/
// @version 0.2
// @description Re-adds issue, comment, and pull request notifications to the dashboard. Messy code warning.
// @author Nukem9
// @match https://github.com/
// @grant none
// ==/UserScript==
// !!! UPDATE THIS !!!
var g_apiURL = "https://api.github.com/users/YOUR_USERNAME/received_events?oauth_token=YOUR_OAUTH_TOKEN";
var g_responseJSON = undefined;
// First, checks if it isn't implemented yet.
if (!String.prototype.format) {
String.prototype.format = function() {
var args = arguments;
return this.replace(/{(\d+)}/g, function(match, number) {
return typeof args[number] != 'undefined'
? args[number]
: match
;
});
};
}
function getElementDate(githubElem) {
var dateElem = githubElem.getElementsByTagName('relative-time')[0];
return new Date(dateElem.getAttribute('datetime'));
}
function generateIssueOpenClose(notif) {
var commentBody = notif.payload.issue.body;
if (commentBody.length > 150)
commentBody = commentBody.substring(0, 150) + '...';
if (notif.payload.action == 'opened') {
return '<div class="issues_opened"><div class="body"><!-- issues -->' +
'<div class="d-flex border-bottom py-3">' +
'<span class="mr-3">' +
'<a data-hovercard-user-id="{0}" data-octo-click="hovercard-link-click" data-octo-dimensions="link_type:self" href="/{1}" aria-describedby="hovercard-aria-description"><img class="avatar" src="{2}" width="32" height="32" alt="@{1}"></a>'.format(notif.actor.id, notif.actor.login, notif.actor.avatar_url) +
'</span>' +
'<div class="d-flex flex-column width-full">' +
'<div>' +
'<div class="d-flex flex-items-baseline mb-2">' +
'<div>' +
'<a data-hovercard-user-id="{0}" data-octo-click="hovercard-link-click" data-octo-dimensions="link_type:self" class="link-gray-dark no-underline text-bold wb-break-all" href="/{1}" aria-describedby="hovercard-aria-description">{1}</a>'.format(notif.actor.id, notif.actor.login) +
' opened an issue in ' +
'<a class="link-gray-dark no-underline text-bold wb-break-all" href="/{0}">{0}</a>'.format(notif.repo.name) +
'<span class="f6 text-gray-light no-wrap ml-1">' +
'<relative-time datetime="{0}"></relative-time>'.format(notif.payload.issue.updated_at) +
'</span>' +
'</div>' +
'</div>' +
'</div>' +
'<div class="Box p-3">' +
'<svg height="16" aria-label="Issue" class="octicon octicon-issue-opened open d-inline-block mt-1 float-left" viewBox="0 0 14 16" version="1.1" width="14" role="img"><path fill-rule="evenodd" d="M7 2.3c3.14 0 5.7 2.56 5.7 5.7s-2.56 5.7-5.7 5.7A5.71 5.71 0 0 1 1.3 8c0-3.14 2.56-5.7 5.7-5.7zM7 1C3.14 1 0 4.14 0 8s3.14 7 7 7 7-3.14 7-7-3.14-7-7-7zm1 3H6v5h2V4zm0 6H6v2h2v-2z"></path></svg>' +
'<div class="ml-4">' +
'<span class="f4 lh-condensed text-bold text-gray-dark">' +
'<a title="{1}" class="text-gray-dark" aria-label="{1}" href="{0}">{1}</a>'.format(notif.payload.issue.html_url, notif.payload.issue.title) +
'</span>' +
'<span class="f4 text-gray-light ml-1">#{0}</span>'.format(notif.payload.issue.number) +
'<div class="dashboard-break-word lh-condensed mb-2 mt-1">' +
'<p>{0}</p>'.format(commentBody) +
'</div>' +
'</div>' +
'</div>' +
'</div>' +
'</div>' +
'</div></div>';
}
else if (notif.payload.action == 'closed') {
return '<div class="issues_closed"><div class="body"><!-- issues -->' +
'<div class="d-flex border-bottom py-3">' +
'<span class="mr-3">' +
'<a data-hovercard-user-id="{0}" data-octo-click="hovercard-link-click" data-octo-dimensions="link_type:self" href="/{1}" aria-describedby="hovercard-aria-description"><img class="avatar" src="{2}" width="32" height="32" alt="@{1}"></a>'.format(notif.actor.id, notif.actor.login, notif.actor.avatar_url) +
'</span>' +
'<div class="d-flex flex-column width-full">' +
'<div>' +
'<div class="d-flex flex-items-baseline mb-2">' +
'<div>' +
'<a data-hovercard-user-id="{0}" data-octo-click="hovercard-link-click" data-octo-dimensions="link_type:self" class="link-gray-dark no-underline text-bold wb-break-all" href="/{1}" aria-describedby="hovercard-aria-description">{1}</a>'.format(notif.actor.id, notif.actor.login) +
' closed an issue in ' +
'<a class="link-gray-dark no-underline text-bold wb-break-all" href="/{0}">{0}</a>'.format(notif.repo.name) +
'<span class="f6 text-gray-light no-wrap ml-1">' +
'<relative-time datetime="{0}"></relative-time>'.format(notif.payload.issue.updated_at) +
'</span>' +
'</div>' +
'</div>' +
'</div>' +
'<div class="Box p-3">' +
'<svg height="16" aria-label="Issue" class="octicon octicon-issue-closed closed d-inline-block mt-1 float-left" viewBox="0 0 14 16" version="1.1" width="14" role="img"><path fill-rule="evenodd" d="M7 10h2v2H7v-2zm2-6H7v5h2V4zm1.5 1.5l-1 1L12 9l4-4.5-1-1L12 7l-1.5-1.5zM8 13.7A5.71 5.71 0 0 1 2.3 8c0-3.14 2.56-5.7 5.7-5.7 1.83 0 3.45.88 4.5 2.2l.92-.92A6.947 6.947 0 0 0 8 1C4.14 1 1 4.14 1 8s3.14 7 7 7 7-3.14 7-7l-1.52 1.52c-.66 2.41-2.86 4.19-5.48 4.19v-.01z"></path></svg>' +
'<div class="ml-4">' +
'<span class="f4 lh-condensed text-bold text-gray-dark">' +
'<a title="{1}" class="text-gray-dark" aria-label="{1}" href="{0}">{1}</a>'.format(notif.payload.issue.html_url, notif.payload.issue.title) +
'</span>' +
'<span class="f4 text-gray-light ml-1">#{0}</span>'.format(notif.payload.issue.number) +
'<div class="dashboard-break-word lh-condensed mb-2 mt-1">' +
'<p>{0}</p>'.format(commentBody) +
'</div>' +
'</div>' +
'</div>' +
'</div>' +
'</div>' +
'</div></div>';
}
}
function generateIssueComment(notif) {
var commentBody = notif.payload.comment.body;
if (commentBody.length > 150)
commentBody = commentBody.substring(0, 150) + '...';
return '<div class="issues_comment"><div class="body">' +
'<!-- issue_comment -->' +
'<div class="d-flex border-bottom border-gray py-3">' +
'<span class="mr-3">' +
'<a data-hovercard-user-id="{0}" data-octo-click="hovercard-link-click" data-octo-dimensions="link_type:self" href="/{1}" aria-describedby="hovercard-aria-description"><img class="avatar" src="{2}" width="32" height="32" alt="@{1}"></a>'.format(notif.actor.id, notif.actor.login, notif.actor.avatar_url) +
'</span>' +
'<div class="d-flex flex-column width-full">' +
'<div class="d-flex flex-items-baseline mb-2">' +
'<div>' +
'<a data-hovercard-user-id="{0}" data-octo-click="hovercard-link-click" data-octo-dimensions="link_type:self" class="link-gray-dark no-underline text-bold wb-break-all" href="/{1}" aria-describedby="hovercard-aria-description">{1}</a>'.format(notif.actor.id, notif.actor.login) +
' commented on issue ' +
'<a class="link-gray-dark text-bold" title="{0}" href="{1}">{2}#{3}</a>'.format(notif.payload.comment.title, notif.payload.comment.html_url, notif.repo.name, notif.payload.issue.number) +
'<span class="f6 text-gray-light ml-1">' +
'<relative-time datetime="{0}"></relative-time>'.format(notif.payload.comment.updated_at) +
'</span>' +
'</div>' +
'</div>' +
'<div class="message markdown-body Box p-3">' +
'<div class="f6 mb-1">' +
'<a title="{0}" class="link-gray" href="{1}"><img class="avatar mr-1" src="{2}" width="16" height="16" alt="@{3}"> <span class="link-gray-dark text-bold">{3}</span> commented <relative-time datetime="{4}"></relative-time></a>'.format(notif.payload.comment.title, notif.payload.comment.html_url, notif.actor.avatar_url, notif.actor.login, notif.payload.comment.updated_at) +
'</div>' +
'<p>{0}</p>'.format(commentBody) +
'</div>' +
'</div>' +
'</div>' +
'</div></div>';
}
function generatePullOpenClose(notif) {
if (notif.payload.action == 'opened') {
var commentBody = notif.payload.pull_request.body;
if (commentBody.length > 150)
commentBody = commentBody.substring(0, 150) + '...';
return '<div class="issues_comment"><div class="body"><!-- issue_comment -->' +
'<div class="d-flex border-bottom border-gray py-3">' +
'<span class="mr-3">' +
'<a data-hovercard-user-id="{0}" data-octo-click="hovercard-link-click" data-octo-dimensions="link_type:self" href="/{1}" aria-describedby="hovercard-aria-description"><img class="avatar" src="{2}" width="32" height="32" alt="@{1}"></a>'.format(notif.actor.id, notif.actor.login, notif.actor.avatar_url) +
'</span>' +
'<div class="d-flex flex-column width-full">' +
'<div>' +
'<div class="d-flex flex-items-baseline">' +
'<div>' +
'<a data-hovercard-user-id="{0}" data-octo-click="hovercard-link-click" data-octo-dimensions="link_type:self" class="link-gray-dark no-underline text-bold wb-break-all" href="/{1}" aria-describedby="hovercard-aria-description">{1}</a>'.format(notif.actor.id, notif.actor.login) +
' opened a pull request in ' +
'<a class="link-gray-dark text-bold" href="/{0}">{0}</a>'.format(notif.repo.name) +
'<span class="f6 text-gray-light ml-1">' +
'<relative-time datetime="{0}"></relative-time>'.format(notif.payload.pull_request.updated_at) +
'</span>' +
'</div>' +
'</div>' +
'</div>' +
'<div class="Box p-3 my-2">' +
'<svg aria-label="Pull request" class="octicon octicon-git-pull-request open d-inline-block mt-1 float-left" height="16" role="img" version="1.1" viewBox="0 0 12 16" width="12"><path fill-rule="evenodd" d="M11 11.28V5c-.03-.78-.34-1.47-.94-2.06C9.46 2.35 8.78 2.03 8 2H7V0L4 3l3 3V4h1c.27.02.48.11.69.31.21.2.3.42.31.69v6.28A1.993 1.993 0 0 0 10 15a1.993 1.993 0 0 0 1-3.72zm-1 2.92c-.66 0-1.2-.55-1.2-1.2 0-.65.55-1.2 1.2-1.2.65 0 1.2.55 1.2 1.2 0 .65-.55 1.2-1.2 1.2zM4 3c0-1.11-.89-2-2-2a1.993 1.993 0 0 0-1 3.72v6.56A1.993 1.993 0 0 0 2 15a1.993 1.993 0 0 0 1-3.72V4.72c.59-.34 1-.98 1-1.72zm-.8 10c0 .66-.55 1.2-1.2 1.2-.65 0-1.2-.55-1.2-1.2 0-.65.55-1.2 1.2-1.2.65 0 1.2.55 1.2 1.2zM2 4.2C1.34 4.2.8 3.65.8 3c0-.65.55-1.2 1.2-1.2.65 0 1.2.55 1.2 1.2 0 .65-.55 1.2-1.2 1.2z"></path></svg>' +
'<div class="ml-4">' +
'<div>' +
'<span class="f3 lh-condensed text-bold text-gray-dark"><a href="{0}" aria-label="{1}" class="text-gray-dark text-bold" style="font-size: 15px !important">{1}</a></span>'.format(notif.payload.pull_request.html_url, notif.payload.pull_request.title) +
'<span class="f4 text-gray-light ml-1">#{0}</span>'.format(notif.payload.pull_request.number) +
'<p class="text-gray mt-1 mb-0">' +
'</p><p>{0}</p>'.format(commentBody) +
'<p></p>' +
'</div>' +
'<div class="diffstat d-inline-block tooltipped tooltipped-se" aria-label="{0} commit with {1} additions and {2} deletions">'.format(notif.payload.pull_request.commits, notif.payload.pull_request.additions, notif.payload.pull_request.deletions) +
'<span class="text-green">+{0}</span>'.format(notif.payload.pull_request.additions) +
'<span class="text-red">&nbsp;-{0}</span>'.format(notif.payload.pull_request.deletions) +
'</div>' +
'</div>' +
'</div>' +
'</div>' +
'</div>' +
'</div>' +
'</div></div>';
}
else if (notif.payload.action == 'closed') {
return '<div class="issues_comment"><div class="body"><!-- issue_comment -->' +
'<div class="d-flex border-bottom border-gray py-3">' +
'<span class="mr-3">' +
'<a data-hovercard-user-id="{0}" data-octo-click="hovercard-link-click" data-octo-dimensions="link_type:self" href="/{1}" aria-describedby="hovercard-aria-description"><img class="avatar" src="{2}" width="32" height="32" alt="@{1}"></a>'.format(notif.actor.id, notif.actor.login, notif.actor.avatar_url) +
'</span>' +
'<div class="d-flex flex-column width-full">' +
'<div>' +
'<div class="d-flex flex-items-baseline">' +
'<div>' +
'<a data-hovercard-user-id="{0}" data-octo-click="hovercard-link-click" data-octo-dimensions="link_type:self" class="link-gray-dark no-underline text-bold wb-break-all" href="/{1}" aria-describedby="hovercard-aria-description">{1}</a>'.format(notif.actor.id, notif.actor.login) +
' closed a pull request in ' +
'<a class="link-gray-dark text-bold" href="/{0}">{0}</a>'.format(notif.repo.name) +
'<span class="f6 text-gray-light ml-1">' +
'<relative-time datetime="{0}"></relative-time>'.format(notif.payload.pull_request.updated_at) +
'</span>' +
'</div>' +
'</div>' +
'</div>' +
'<div class="Box p-3 my-2">' +
'<svg aria-label="Pull request" class="octicon octicon-git-pull-request open d-inline-block mt-1 float-left" height="16" role="img" version="1.1" viewBox="0 0 12 16" width="12"><path fill-rule="evenodd" d="M11 11.28V5c-.03-.78-.34-1.47-.94-2.06C9.46 2.35 8.78 2.03 8 2H7V0L4 3l3 3V4h1c.27.02.48.11.69.31.21.2.3.42.31.69v6.28A1.993 1.993 0 0 0 10 15a1.993 1.993 0 0 0 1-3.72zm-1 2.92c-.66 0-1.2-.55-1.2-1.2 0-.65.55-1.2 1.2-1.2.65 0 1.2.55 1.2 1.2 0 .65-.55 1.2-1.2 1.2zM4 3c0-1.11-.89-2-2-2a1.993 1.993 0 0 0-1 3.72v6.56A1.993 1.993 0 0 0 2 15a1.993 1.993 0 0 0 1-3.72V4.72c.59-.34 1-.98 1-1.72zm-.8 10c0 .66-.55 1.2-1.2 1.2-.65 0-1.2-.55-1.2-1.2 0-.65.55-1.2 1.2-1.2.65 0 1.2.55 1.2 1.2zM2 4.2C1.34 4.2.8 3.65.8 3c0-.65.55-1.2 1.2-1.2.65 0 1.2.55 1.2 1.2 0 .65-.55 1.2-1.2 1.2z"></path></svg>' +
'<div class="ml-4">' +
'<div>' +
'<span class="f3 lh-condensed text-bold text-gray-dark"><a href="{0}" aria-label="{1}" class="text-gray-dark text-bold" style="font-size: 15px !important">{1}</a></span>'.format(notif.payload.pull_request.html_url, notif.payload.pull_request.title) +
'<span class="f4 text-gray-light ml-1">#{0}</span>'.format(notif.payload.pull_request.number) +
'</div>' +
'</div>' +
'</div>' +
'</div>' +
'</div>' +
'</div>' +
'</div></div>';
}
}
function generatePullComment(notif) {
var commentBody = notif.payload.comment.body;
if (commentBody.length > 150)
commentBody = commentBody.substring(0, 150) + '...';
return '<div class="issues_comment"><div class="body"><!-- issue_comment -->' +
'<div class="d-flex border-bottom border-gray-light py-3">' +
'<a href="/{0}"><img alt="@{0}" class="avatar mr-3" height="32" src="{1}" width="32"></a>'.format(notif.actor.login, notif.actor.avatar_url) +
'<div class="d-flex flex-column width-full">' +
'<div>' +
'<div class="d-flex flex-justify-between flex-items-baseline">' +
'<div>' +
'<a class="link-gray-dark text-bold" href="/{0}">{0}</a> commented on pull request <a class="link-gray-dark text-bold" href="{1}">{2}#{3}</a>'.format(notif.actor.login, notif.payload.comment.html_url, notif.repo.name, notif.payload.pull_request.number) +
'</div>' +
'<span class="f6 text-gray-light ml-4">' +
'<relative-time datetime="{0}"></relative-time>'.format(notif.payload.comment.updated_at) +
'</span>' +
'</div>' +
'</div>' +
'<div class="message markdown-body mt-3">' +
'<blockquote style="border-left: 0 !important">' +
'<p>{0}</p>'.format(commentBody) +
'</blockquote>' +
'</div>' +
'</div>' +
'</div>' +
'</div></div>';
}
function insertGitHubNotification(prevElement, notif, before) {
'use strict';
var newData = undefined;
if (notif.type == "IssuesEvent")
newData = generateIssueOpenClose(notif);
else if (notif.type == "IssueCommentEvent")
newData = generateIssueComment(notif);
else if (notif.type == "PullRequestEvent")
newData = generatePullOpenClose(notif);
else if (notif.type == "PullRequestReviewCommentEvent")
newData = generatePullComment(notif);
else if (notif.type == "WatchEvent") // Exists by default
newData = undefined;
else if (notif.type == "PushEvent") // Exists by default
newData = undefined;
if (newData === undefined)
return;
var newElem = document.createElement("div");
newElem.innerHTML = newData;
if (before === true)
prevElement.parentNode.insertBefore(newElem, prevElement);
else
prevElement.parentNode.insertAfter(newElem, prevElement);
}
function fetchJSON() {
'use strict';
if (g_responseJSON != undefined) {
return;
}
// Fetch all notifications for user
var xhttp = new XMLHttpRequest();
xhttp.open("GET", g_apiURL, true);
xhttp.setRequestHeader("Content-Type", "application/json");
xhttp.onload = function(e) {
g_responseJSON = JSON.parse(xhttp.responseText);
};
xhttp.send();
}
function isValidClass(elemClassType) {
switch(elemClassType.trim()) {
case 'push':
case 'watch_started':
case 'release':
case 'gollum':// wiki edits
case 'follow':
case 'fork':
case 'star':
case 'release':
case 'issues_comment':// also counts for PR
case 'issues_closed': // also counts for PR
case 'issues_opened': // also counts for PR
return true;
}
return false;
}
function maincode() {
'use strict';
fetchJSON();
var dashboardElems = document.getElementById('dashboard').children[0];// "dashboard" -> "news"
var childElems = ([].slice.call(dashboardElems.children)).filter(x => isValidClass(x.className));
if (childElems.length <= 0 || g_responseJSON == undefined || g_responseJSON.length == 0) {
return 0;
}
for (var i = 0; i < childElems.length; i++) {
var startDate = getElementDate(childElems[i]);
// Now find the posts which should be in this date range (childElems is already in order, newest first)
for (var j = 0; j < g_responseJSON.length; j++) {
var respDate = new Date(g_responseJSON[j].created_at);
// If (notification is newer than current activity entry) { add_html(); remove_from_array(); }
if (respDate >= startDate) {
insertGitHubNotification(childElems[i], g_responseJSON[j], true);
g_responseJSON.splice(j, 1);
j--;
continue;
}
}
}
return 1;
}
var tm_mytimer = setInterval(function(){ if (maincode() == 1) clearInterval(tm_mytimer); }, 100);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment