Skip to content

Instantly share code, notes, and snippets.

@bowmande
Created August 22, 2014 14:58
Show Gist options
  • Save bowmande/9c6421b035df13dcd2cf to your computer and use it in GitHub Desktop.
Save bowmande/9c6421b035df13dcd2cf to your computer and use it in GitHub Desktop.
// ==UserScript==
// @name Add Points to Jira Board
// @namespace http://use.i.E.your.homepage/
// @version 0.1
// @description enter something useful
// @match http://tampermonkey.net/index.php?version=3.8.52&ext=dhdg&updated=true
// @copyright 2012+, You
// ==/UserScript==
// see https://jira.atlassian.com/browse/GHS-6755
//
// CHANGELOG:
// V1.2 (2014-07-09):
// - also display total number of story points per stream
// - also update stories with no storypoints ('0 SP')
// V1.1 (2014-03-06):
// - also update empty columns ('0 SP')
// V1.0 (2013-07-02):
// - instead of periodically updating the SPs, use GreenHopper's 'workModeUIReady' event
// V0.3 (2013-05-01):
// - fetch more results when there are more User Stories than our max-results (500)
// V0.2 (2013-03-21):
// - fetch all issues at once per column (instead of per user story; saves a lot of REST calls)
// V0.1 (2013-02-26):
// - initial version
function processSPs() {
try {
var spByIssueId = {};
// fieldId of field containing user story points
var SP_FIELD = "customfield_10004";
var restApiBaseUrl = document.location.protocol+"//"+document.location.host;
if (GH.Ajax.CONTEXT_PATH && GH.Ajax.CONTEXT_PATH.length>0) {
restApiBaseUrl += "/"+GH.Ajax.CONTEXT_PATH;
}
// function is perform a 'GET' REST call
function getJson(restUrl, callback, callbackError) {
return jQuery.ajax({
type: "GET",
url: restUrl,
success: callback,
dataType: "json",
contentType: "application/json; charset=utf-8",
error: callbackError
});
}
// function which displays the specified story points inside its own span inside the specified container
function setSPSpanValue(jQContainers, sp) {
jQuery.each(jQContainers, function() {
jQContainer = jQuery(this);
var spDiv = jQContainer.find(".sp-flag");
if (spDiv.length===0) {
spDiv = jQuery("<span class='sp-flag' style='margin-left: 5px; font-weight: bold'></span>").appendTo(jQContainer);
}
spDiv.html("("+sp+" SP)");
});
}
jQuery("#ghx-board-name").css("display", "inline");
function processColumn(boardInfo, columnInfo) {
var statusIds = columnInfo.statusIds;
// collect all issue keys of the current column
var issueKeys = _.map(boardInfo.issuesData.issues, function(issueData) {
if (jQuery.inArray(String(issueData.statusId), statusIds)!==-1) {
return issueData.key;
}
return null;
});
issueKeys = _.without(issueKeys, null);
return searchIssues(issueKeys, columnInfo.id, 0, 0);
}
var grandTotalSP = 0;
function searchIssues(issueKeys, dataId, startAt, totalSP, deferred) {
if (!deferred) {
deferred = jQuery.Deferred();
}
var jQHeader = jQuery(".ghx-column-headers li[data-id="+dataId+"] h2");
jQHeader.css("display", "inline");
if (issueKeys.length==0) {
setSPSpanValue(jQHeader, 0);
return deferred.resolve();
}
var url = restApiBaseUrl+"/rest/api/2/search?jql=key in ("+issueKeys+")&fields="+SP_FIELD+"&maxResults=500";
getJson(url+"&startAt="+startAt, function(searchResult) {
jQuery.each(searchResult.issues, function(i, issue) {
if (issue.fields && issue.fields[SP_FIELD]!=null) {
var sp = issue.fields[SP_FIELD];
setSPSpanValue(jQuery(".ghx-issue[data-issue-key='"+issue.key+"'] .ghx-key"), sp);
spByIssueId[issue.id] = sp;
totalSP += sp;
totalSP = Math.round(totalSP*100)/100;
}
});
setSPSpanValue(jQHeader, totalSP);
grandTotalSP += totalSP;
grandTotalSP = Math.round(grandTotalSP*100)/100;
var boardTitle = jQuery("#ghx-view-selector");
setSPSpanValue(boardTitle, grandTotalSP);
var callStartAt = searchResult.startAt||0;
if (startAt+searchResult.issues.length < searchResult.total) {
searchIssues(issueKeys, dataId, startAt+searchResult.maxResults, totalSP, deferred);
}
else {
deferred.resolve();
}
});
return deferred;
}
var rapidViewId = GH.RapidBoard.State.data.rapidViewId;
if (rapidViewId) {
var url = restApiBaseUrl+GH.Ajax.REST_URL_BASE+"/xboard/work/allData/?rapidViewId="+rapidViewId;
getJson(url, function(boardInfo) {
var promises = [];
var i;
for (i=0; i<boardInfo.columnsData.columns.length; i++) {
var columnInfo = boardInfo.columnsData.columns[i];
var deferred = processColumn(boardInfo, columnInfo);
promises.push(deferred);
}
var swimlanes = boardInfo.swimlanesData[boardInfo.swimlanesData.swimlaneStrategy+"SwimlanesData"].swimlanes;
jQuery.when.apply(jQuery, promises).done(function() {
for (i=0; i<swimlanes.length; i++) {
var swimlane = swimlanes[i];
var totalSP = 0;
// update columns and the stories in the columns
var j;
for (j=0; j<swimlane.issueIds.length; j++) {
var issueId = swimlane.issueIds[j];
var sp = spByIssueId[issueId+""];
if (sp) {
totalSP += sp;
}
}
// update swimlane total sps
var $swimlaneDiv = jQuery(".ghx-swimlane-header[data-swimlane-id="+swimlane.id+"] .ghx-heading");
totalSP = Math.round(totalSP*100)/100;
setSPSpanValue($swimlaneDiv, totalSP);
}
});
});
}
}
catch (e) {
console.log("processSPs error occured", e);
}
}
jQuery().ready(function() {
AJS.$(GH).bind('workModeUIReady', function() {
processSPs();
});
});
@lukasrossa
Copy link

Hi, how did you discover the 'workModeUIReady' event? I'm trying to find out more information about the events the RapidBoard sends but am having little luck.

@zFly
Copy link

zFly commented Sep 11, 2018

Hi @lukasrossa,
I was facing the same issue and was able to get the information with jQuery._data( AJS.$(GH).get(0), "events" );

Unfortunately these events get not triggered when viewing the Backlog...

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment