The script scans your JIRA Agile Kanban board, calculates the combined WIP limits for all “column groups” (columns with the same start of the column name, like DEV in “DEV analysis” and “DEV ongoing” or QA in “QA ongoing” and “QA done”) and applies a yellow background to all columns of a group where the joint WIP limit is already reached and a red background to all columns of a group where the joint WIP limit is violated. The result will look similar to the example screenshot below (where the WIP limit is violated in the QA columns).
// ==UserScript== // @name Jira Rapid Board combined limits // @namespace Jira // @include https://jira.****.com/secure/RapidBoard.jspa* // @version 1 // @grant none // ==/UserScript== (function jiraRapidBoardCombinedLimits($) { function refreshLimits() { var groups = {}; var classesForColumns = {}; var $header = $('ul#ghx-column-headers'); console.log("find headers"); console.log($header); $header.find('li.ghx-column').each(function () { min = 0; var $column = $(this); var groupKey = $column.children('h2').text().split(/ /)[0]; var min = parseInt($('.ghx-limits .ghx-busted-min', $column).text().replace("Min ", "")); var max = parseInt($('.ghx-limits .ghx-busted-max', $column).text().replace("Max ", "")); var current = parseInt($('.ghx-qty', $column).text()); if (!groups[groupKey]) { groups[groupKey] = { $columns: $(), current: 0 }; } var group = groups[groupKey]; group.$columns = group.$columns.add($column); if (min) group.min = group.min ? group.min + min : min; if (max) group.max = group.max ? group.max + max : max; group.current = group.current + current; //alert("hola"); }); for (var groupKey in groups) { var group = groups[groupKey]; console.log("Limit group " + groupKey, group); var $limit = $(' <div class="ghx-x-limit-combined"></div> '); if (group.current && group.max) { $limit.text('Combined: ' + group.current + ' of ' + group.max); var addClass = null; if (group.current == group.max) addClass = 'ghx-x-limit-warning'; if (group.current > group.max) addClass = 'ghx-x-limit-fail'; group.$columns.each(function () { console.log(this); classesForColumns[$(this).data().id] = addClass; }); } group.$columns.children('.ghx-x-limit-combined').remove(); group.$columns.append($limit); } console.log("Classes for columns: ", classesForColumns); $('#ghx-pool .ghx-swimlane .ghx-column').each(function () { var $cell = $(this); group.$columns.removeClass("ghx-x-limit-warning ghx-x-limit-fail"); $cell.addClass(classesForColumns[$cell.data().columnId]); }); } $(function () { var css = ".ghx-column.ghx-x-limit-warning { background-color: yellow; } " + ".ghx-column.ghx-x-limit-fail { background-color: #ff6666; } " + ".ghx-x-limit-combined { position: absolute; bottom: 0; font-size: 11px; color: #707070 }"; $('head').append($(' <style></style> ').html(css)) refreshLimits(); var handlerActive = false; $("#ghx-pool").live("DOMNodeInserted", function (event) { var $this = $(event.target); console.log("jiraRapidBoardCombinedLimits: Caught " + event.type, $this); if ($this.closest('#ghx-column-header-group').length > 0 && !handlerActive) { handlerActive = true; refreshLimits(); handlerActive = false; } }); }); }(jQuery));