Skip to content

Highligh status? #31

Open
harley opened this issue Feb 18, 2026 · 0 comments
Open

Highligh status? #31

harley opened this issue Feb 18, 2026 · 0 comments

Comments

@harley
Copy link

harley commented Feb 18, 2026

For the status on a ticket, consider adding a highlight as displayed in the attached image.

Image

Example code from Travis Kirby.

`// ==UserScript==
// @name Highlight Workflow Statuses (In Process, Awaiting Customer, Pending)
// @namespace https://github.com/
// @version 1.2
// @description Highlights "In Process" (red), "Awaiting Customer Response" (green), "Pending External/Internal" (orange) with boxes — only on Purdue TDWorkManagement
// @author You
// @match https://service.purdue.edu/TDWorkManagement/*
// @grant none
// @run-at document-end
// ==/UserScript==

(function() {
'use strict';

const STYLE_ID = 'workflow-status-highlight-style';

// Add styles only once
if (!document.getElementById(STYLE_ID)) {
    const style = document.createElement('style');
    style.id = STYLE_ID;
    style.textContent = `
        .status-in-process {
            border: 2px solid #ff3333 !important;
            border-radius: 4px !important;
            background-color: rgba(255, 60, 60, 0.12) !important;
            color: white !important;
            padding: 2px 5px !important;
            display: inline-block !important;
            line-height: 1.4 !important;
            box-decoration-break: clone;
            -webkit-box-decoration-break: clone;
        }

        .status-awaiting-customer {
            border: 2px solid #33cc33 !important;
            border-radius: 4px !important;
            background-color: rgba(51, 204, 51, 0.12) !important;
            color: white !important;
            padding: 2px 5px !important;
            display: inline-block !important;
            line-height: 1.4 !important;
            box-decoration-break: clone;
            -webkit-box-decoration-break: clone;
        }

        .status-pending {
            border: 2px solid #ff9900 !important;
            border-radius: 4px !important;
            background-color: rgba(255, 153, 0, 0.14) !important;
            color: white !important;
            padding: 2px 5px !important;
            display: inline-block !important;
            line-height: 1.4 !important;
            box-decoration-break: clone;
            -webkit-box-decoration-break: clone;
        }
    `;
    document.head.appendChild(style);
}

function highlightStatuses() {
    const walker = document.createTreeWalker(
        document.body,
        NodeFilter.SHOW_TEXT,
        {
            acceptNode: function(node) {
                if (!node.parentNode) return NodeFilter.FILTER_REJECT;
                const parent = node.parentNode;
                if (parent.nodeName === 'SCRIPT' ||
                    parent.nodeName === 'STYLE' ||
                    parent.nodeName === 'NOSCRIPT' ||
                    parent.classList.contains('status-in-process') ||
                    parent.classList.contains('status-awaiting-customer') ||
                    parent.classList.contains('status-pending')) {
                    return NodeFilter.FILTER_REJECT;
                }
                return NodeFilter.FILTER_ACCEPT;
            }
        }
    );

    const textNodes = [];
    let node;
    while (node = walker.nextNode()) {
        textNodes.push(node);
    }

    for (const textNode of textNodes) {
        const text = textNode.nodeValue;
        if (!text) continue;

        const replacements = [];

        // In Process
        let regex = /\bIn Process\b/gi;   // case-insensitive
        let match;
        while ((match = regex.exec(text)) !== null) {
            replacements.push({
                start: match.index,
                end: regex.lastIndex,
                className: 'status-in-process',
                text: match[0]
            });
        }

        // Awaiting Customer Response
        regex = /\bAwaiting Customer Response\b/gi;
        while ((match = regex.exec(text)) !== null) {
            replacements.push({
                start: match.index,
                end: regex.lastIndex,
                className: 'status-awaiting-customer',
                text: match[0]
            });
        }

        // Pending External / Pending Internal
        regex = /\bPending (?:External|Internal)\b/gi;
        while ((match = regex.exec(text)) !== null) {
            replacements.push({
                start: match.index,
                end: regex.lastIndex,
                className: 'status-pending',
                text: match[0]
            });
        }

        if (replacements.length === 0) continue;

        // Sort by start position
        replacements.sort((a, b) => a.start - b.start);

        let lastIndex = 0;
        const fragment = document.createDocumentFragment();

        for (const rep of replacements) {
            if (rep.start > lastIndex) {
                fragment.appendChild(
                    document.createTextNode(text.slice(lastIndex, rep.start))
                );
            }

            const span = document.createElement('span');
            span.className = rep.className;
            span.textContent = rep.text;
            fragment.appendChild(span);

            lastIndex = rep.end;
        }

        if (lastIndex < text.length) {
            fragment.appendChild(
                document.createTextNode(text.slice(lastIndex))
            );
        }

        textNode.parentNode.replaceChild(fragment, textNode);
    }
}

// Initial run (delayed slightly for dynamic content)
setTimeout(highlightStatuses, 400);

// Watch for DOM changes (very useful in TeamDynamix SPA-like interfaces)
const observer = new MutationObserver(() => {
    setTimeout(highlightStatuses, 80);
});

observer.observe(document.body, {
    childList: true,
    subtree: true,
    characterData: true   // also catch text changes
});

})();`

Sign in to join this conversation on GitHub.
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant