nhemmerson / Zendesk SLA Threshold Override

// ==UserScript==
// @name         Zendesk SLA Threshold Override
// @namespace    http://tampermonkey.net/
// @version      0.1
// @description  Make SLA badges turn yellow at 1 h remaining, red at 15 min remaining (instead of Zendesk’s defaults).
// @author       You
// @match        https://*.zendesk.com/*
// @grant        none
// @license      MIT
// ==/UserScript==

(function() {
  'use strict';

  // 1) Inject CSS with !important
  const css = `
    [data-garden-id="tags.tag_view"].sla-green  { background-color: #5cb85c !important; color: white !important; }
    [data-garden-id="tags.tag_view"].sla-yellow { background-color: #f0ad4e !important; color: black !important; }
    [data-garden-id="tags.tag_view"].sla-red    { background-color: #d9534f !important; color: white !important; }
  `;
  const style = document.createElement('style');
  style.textContent = css;
  document.head.appendChild(style);

  // 2) Color‐decider: read the text and apply the right class
  function colorize(timeEl) {
    const txt = timeEl.textContent.trim();
    const badge = timeEl.closest('[data-garden-id="tags.tag_view"]');
    if (!badge) return;

    badge.classList.remove('sla-green','sla-yellow','sla-red');

    const m = txt.match(/^(\d+)\s*m$/i);
    if (m) {
      const mins = parseInt(m[1], 10);
      if (mins <= 15)            badge.classList.add('sla-red');
      else if (mins <= 59)       badge.classList.add('sla-yellow');
      else                       badge.classList.add('sla-green');
    } else {
      // hours or days → green
      badge.classList.add('sla-green');
    }
  }

  // 3) Scan all badges on the page
  function scanAll() {
    document
      .querySelectorAll('[data-garden-id="tags.tag_view"] time')
      .forEach(colorize);
  }

  // 4) Watch for new badges (React will re-render them dynamically)
  const obs = new MutationObserver(muts => {
    for (let m of muts) {
      for (let node of m.addedNodes) {
        if (node.nodeType !== 1) continue;
        if (
          node.matches('[data-garden-id="tags.tag_view"]') ||
          node.querySelector('[data-garden-id="tags.tag_view"]')
        ) {
          scanAll();
          return;
        }
      }
    }
  });
  obs.observe(document.body, { childList: true, subtree: true });

  // 5) Fallback runs (in case some get missed)
  setInterval(scanAll, 10000);
  window.addEventListener('load', () => setTimeout(scanAll, 2000));
})();