Jira Task Priority Colorizer and Emoji Notifier

Change card colors based on Jira task priority and add emoji if task is in status for more than 3 days

目前為 2024-10-11 提交的版本,檢視 最新版本

  1. // ==UserScript==
  2. // @name Jira Task Priority Colorizer and Emoji Notifier
  3. // @namespace http://tampermonkey.net/
  4. // @version 0.2
  5. // @description Change card colors based on Jira task priority and add emoji if task is in status for more than 3 days
  6. // @author
  7. // @include https://*/secure/RapidBoard.jspa*
  8. // @grant none
  9. // @license MIT
  10. // ==/UserScript==
  11.  
  12. (function() {
  13. 'use strict';
  14.  
  15. const styleContent = `
  16. .ghx-issue[data-priority*="P0"] {
  17. background-color: #FFADB0 !important;
  18. }
  19. .ghx-issue[data-priority*="P1"] {
  20. background-color: #FF8488 !important;
  21. }
  22. .ghx-issue[data-priority*="P2"] {
  23. background-color: #FFD3C6 !important;
  24. }
  25. .ghx-issue[data-priority*="P3"],
  26. .ghx-issue[data-priority*="P4"] {
  27. background-color: #FFF !important;
  28. }
  29. .stale-emoji {
  30. position: absolute;
  31. bottom: 5px;
  32. right: 5px;
  33. font-size: 32px;
  34. display: flex;
  35. align-items: center;
  36. }
  37. .stale-emoji span {
  38. margin-left: 5px;
  39. font-size: 16px;
  40. color: #000;
  41. }
  42. .ghx-issue {
  43. position: relative;
  44. }
  45. `;
  46.  
  47. const styleElement = document.createElement('style');
  48. styleElement.type = 'text/css';
  49. styleElement.appendChild(document.createTextNode(styleContent));
  50. document.head.appendChild(styleElement);
  51.  
  52. function updateCardPriorities() {
  53. let cards = document.querySelectorAll('.ghx-issue');
  54.  
  55. cards.forEach(card => {
  56. let priorityElement = card.querySelector('.ghx-priority');
  57. if (priorityElement) {
  58. let priority = priorityElement.getAttribute('title') || priorityElement.getAttribute('aria-label') || priorityElement.innerText || priorityElement.textContent;
  59. if (priority) {
  60. card.setAttribute('data-priority', priority);
  61. }
  62. }
  63.  
  64. let daysElement = card.querySelector('.ghx-days');
  65. if (daysElement) {
  66. let title = daysElement.getAttribute('title');
  67. if (title) {
  68. let daysMatch = title.match(/(\d+)\s+days?/);
  69. if (daysMatch && daysMatch[1]) {
  70. let daysInColumn = parseInt(daysMatch[1], 10);
  71. if (daysInColumn >= 3) {
  72. let existingEmoji = card.querySelector('.stale-emoji');
  73. if (!existingEmoji) {
  74. let emojiContainer = document.createElement('div');
  75. emojiContainer.className = 'stale-emoji';
  76.  
  77. let emojiElement = document.createElement('span');
  78. emojiElement.textContent = '💩';
  79.  
  80. let daysText = document.createElement('span');
  81. daysText.textContent = daysInColumn + 'd';
  82.  
  83. emojiContainer.appendChild(emojiElement);
  84. emojiContainer.appendChild(daysText);
  85.  
  86. card.appendChild(emojiContainer);
  87. } else {
  88. let daysText = existingEmoji.querySelector('span:last-child');
  89. daysText.textContent = daysInColumn + ' d';
  90. }
  91. } else {
  92. let existingEmoji = card.querySelector('.stale-emoji');
  93. if (existingEmoji) {
  94. existingEmoji.remove();
  95. }
  96. }
  97. }
  98. }
  99. }
  100. });
  101. }
  102.  
  103. const observer = new MutationObserver(() => {
  104. updateCardPriorities();
  105. });
  106.  
  107. observer.observe(document.body, { childList: true, subtree: true });
  108.  
  109. window.addEventListener('load', function() {
  110. updateCardPriorities();
  111. });
  112.  
  113. setInterval(updateCardPriorities, 5000);
  114. })();