Skip to content

Instantly share code, notes, and snippets.

@SVNKoch
Last active June 30, 2025 13:16
Show Gist options
  • Select an option

  • Save SVNKoch/90a76c8e265267b8b23a7f954bc82c24 to your computer and use it in GitHub Desktop.

Select an option

Save SVNKoch/90a76c8e265267b8b23a7f954bc82c24 to your computer and use it in GitHub Desktop.
Jira Data Center & Cloud Administration: Issue Statuses Reordering for StatusCategory
// ==UserScript==
// @name Jira Reorder Statuses in Admin Page by StatusCategory (no-reload)
// @namespace jira.violentmonkey.userscript
// @match *://*/*/ViewStatuses.jspa*
// @version 2.0
// @description Orders entries by status: "To Do" < "In Progress" < "Done" without reloading between moves
// @grant none
// ==/UserScript==
(() => {
'use strict';
const CATEGORY_ORDER = { 'To Do': 0, 'In Progress': 1, 'Done': 2 };
const STEP_DELAY = 300; // ms pause between server calls
const HIGHLIGHT = false; // true = visual trace for each move
const tooltipSel = "td.overflow-ellipsis span[data-tooltip*='jira-issue-status-tooltip-title']";
const $all = (sel, ctx = document) => Array.from(ctx.querySelectorAll(sel));
const rows = () => $all('tbody tr');
const catOf = row => {
const span = row.querySelector(tooltipSel);
if (!span) return null;
const tip = span.getAttribute('data-tooltip') || '';
return Object.keys(CATEGORY_ORDER).find(c => tip.includes(c));
};
const domSwapUp = row => {
const prev = row.previousElementSibling;
if (prev) prev.before(row);
};
const pingServer = url => fetch(url, { credentials: 'include', method: 'GET' });
const nextMove = () => {
const r = rows();
for (let i = 1; i < r.length; i++) {
const cur = catOf(r[i]);
const prev = catOf(r[i - 1]);
if (cur && prev && CATEGORY_ORDER[cur] < CATEGORY_ORDER[prev]) {
const link = r[i].querySelector("a[href*='StatusUp.jspa']");
if (link) return { node: r[i], url: link.href };
}
}
return null;
};
const step = () => {
const m = nextMove();
if (!m) { location.reload(); return; }
if (HIGHLIGHT) {
m.node.style.background = '#ffeb3b';
m.node.scrollIntoView({ behavior: 'smooth', block: 'center' });
}
pingServer(m.url)
.then(() => domSwapUp(m.node))
.finally(() => setTimeout(step, STEP_DELAY));
};
window.addEventListener('load', step);
})();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment