Enhanced AG Grid Functionality with Clean Styles

Adds vibrant row hover effect, conditional status cell styling for test and sample status, static red background for emergency rows, and cleans up styles for specific elements.

Version au 14/04/2025. Voir la dernière version.

Vous devrez installer une extension telle que Tampermonkey, Greasemonkey ou Violentmonkey pour installer ce script.

Vous devrez installer une extension telle que Tampermonkey pour installer ce script.

Vous devrez installer une extension telle que Tampermonkey ou Violentmonkey pour installer ce script.

Vous devrez installer une extension telle que Tampermonkey ou Userscripts pour installer ce script.

Vous devrez installer une extension telle que Tampermonkey pour installer ce script.

Vous devrez installer une extension de gestionnaire de script utilisateur pour installer ce script.

(J'ai déjà un gestionnaire de scripts utilisateur, laissez-moi l'installer !)

Vous devrez installer une extension telle que Stylus pour installer ce style.

Vous devrez installer une extension telle que Stylus pour installer ce style.

Vous devrez installer une extension telle que Stylus pour installer ce style.

Vous devrez installer une extension du gestionnaire de style pour utilisateur pour installer ce style.

Vous devrez installer une extension du gestionnaire de style pour utilisateur pour installer ce style.

Vous devrez installer une extension du gestionnaire de style pour utilisateur pour installer ce style.

(J'ai déjà un gestionnaire de style utilisateur, laissez-moi l'installer!)

// ==UserScript==
// @name         Enhanced AG Grid Functionality with Clean Styles
// @version      3.8
// @description  Adds vibrant row hover effect, conditional status cell styling for test and sample status, static red background for emergency rows, and cleans up styles for specific elements.
// @match        *://his.kaauh.org/lab/*
// @author       Hamad AlShegifi
// @grant        GM_addStyle
// @namespace    http://tampermonkey.net/
// ==/UserScript==

(function () {
    'use strict';

    // Inject CSS for hover effect, status cell styling, and emergency highlighting
    GM_addStyle(`
        .ag-row {
            transition: background-color 0.3s ease;
        }
        .vibrant-hover {
            /* Background color and text color are now applied to cells within the hovered row */
        }
        .ag-row.vibrant-hover .ag-cell {
            background-color: #87dced !important; /* Light blue color */
            color: black !important; /* Black text color */
            font-weight: bold !important; /* Bold font */
        }
        .ag-cell[col-id="testStatus"].status-verified-level2,
        .ag-cell[col-id="testStatus"].status-verified-level1 {
            background-color: #90EE90 !important; /* Light green color */
        }
        .ag-cell[col-id="testStatus"].status-ordered {
            background-color: #FFFFE0 !important; /* Light yellow color */
        }
        .ag-cell[col-id="testStatus"].status-resulted {
            background-color: #FFA500 !important; /* Orange color */
            color: black !important; /* Ensure text is readable on orange */
        }
        .ag-cell[col-id="testStatus"].status-cancelled {
            background-color: #000000 !important; /* Brown color */
            color: white !important; /* White text for contrast */
        }
        .emergency-row {
            background-color: #ffe0e0 !important; /* Light red */
        }
        .ag-cell[col-id="sampleStatus"].status-received {
            background-color: #90EE90 !important; /* Light green color for Received sample status */
        }
    `);

    // Clean styles for specific links and spans
    function applyCleanStyles() {
        const anchor = document.querySelector('li > a[href="#/lab-orders/doctor-request"]');
        if (anchor) {
            anchor.style.setProperty('white-space', 'nowrap', 'important');
            anchor.style.setProperty('font-size', '13px', 'important');
            anchor.style.setProperty('overflow', 'visible', 'important');
            anchor.style.setProperty('text-overflow', 'unset', 'important');

            const spans = anchor.querySelectorAll('span');
            spans.forEach(span => {
                span.style.setProperty('display', 'inline', 'important');
                span.style.setProperty('font-size', '13px', 'important');
                span.style.setProperty('white-space', 'nowrap', 'important');
            });
        }

        const simplifySpan = (selector) => {
            const span = document.querySelector(selector);
            if (span) {
                span.style.setProperty('display', 'inline', 'important');
                span.style.setProperty('font-size', '20px', 'important');
                span.style.setProperty('white-space', 'nowrap', 'important');
                span.style.setProperty('overflow', 'visible', 'important');
                span.style.setProperty('text-overflow', 'unset', 'important');
                span.textContent = span.textContent.replace(/\s+/g, ''); // Optional cleanup
            }
        };

        simplifySpan('span.to-do');
        simplifySpan('span.pending-orders');
    }

    // Debounce for applying clean styles
    function debounce(func, wait) {
        let timeout;
        return function(...args) {
            clearTimeout(timeout);
            timeout = setTimeout(() => func.apply(this, args), wait);
        };
    }

    const debouncedStyleUpdater = debounce(applyCleanStyles, 300);
    const observer = new MutationObserver(debouncedStyleUpdater);
    observer.observe(document.body, { childList: true, subtree: true });

    // Apply hover effects
    const targetColumnIdsForHover = [
        "orderNo", "testId", "testDescription", "clusterMrn",
        "hospitalMrn", "patientName", "dob", "nationalIqamaId",
        "department", "clinic", "doctor", "analyzer",
        "orderDateAndTime", "lastUpdatedDate", "sampleStatus",
        "referenceLab", "accessionNo", "barcode", "sequenceNo",
        "primaryPatientId", "referenceLabDesc", "testStatus",
        "orderLastModifiedOnEpoch", "orderCreatedOnEpoch", "equipmentName", "doctorName", "localMrn",
        "dateOfBirth", "idNumber"
    ];

    function applyHoverEffect() {
        document.querySelectorAll('.ag-cell').forEach(cell => {
            const colId = cell.getAttribute('col-id');
            if (colId && targetColumnIdsForHover.includes(colId)) {
                const row = cell.closest('.ag-row'); // Find the parent row
                if (row) {
                    // Add hover effect to the entire row on mouseenter
                    cell.addEventListener('mouseenter', () => {
                        row.classList.add('vibrant-hover'); // Add hover effect to the row
                    });
                    // Remove hover effect on mouseleave
                    cell.addEventListener('mouseleave', () => {
                        row.classList.remove('vibrant-hover'); // Remove hover effect from the row
                    });
                }
            }
        });
    }

    // Apply conditional background color for test and sample statuses
    function applyStatusCellStyle() {
        document.querySelectorAll('.ag-cell[col-id="testStatus"]').forEach(cell => {
            const statusValue = cell.textContent.trim();
            cell.classList.remove('status-verified-level2', 'status-verified-level1', 'status-ordered', 'status-resulted', 'status-cancelled'); // Remove previous styles

            if (statusValue === "VerifiedLevel2" || statusValue === "VerifiedLevel1") {
                cell.classList.add('status-verified-level2');
            } else if (statusValue === "Ordered") {
                cell.classList.add('status-ordered');
            } else if (statusValue === "Resulted") {
                cell.classList.add('status-resulted');
            } else if (statusValue === "Cancelled") {
                cell.classList.add('status-cancelled'); // Apply brown color for Cancelled
            }
        });

        // Apply style for Sample Status = Received
        document.querySelectorAll('.ag-cell[col-id="sampleStatus"]').forEach(cell => {
            if (cell.textContent.trim() === "Received") {
                cell.classList.add('status-received');
            } else {
                cell.classList.remove('status-received'); // Ensure the class is removed if the value changes
            }
        });
    }

    // Highlight emergency rows based on clinic column
    function highlightEmergencyRows() {
        const rows = document.querySelectorAll('div[role="row"]');
        rows.forEach(row => {
            const clinicCell = row.querySelector('div[col-id="clinic"]');
            if (clinicCell && clinicCell.textContent.trim() === 'EMERGENCY') {
                row.classList.add('emergency-row');
            } else {
                row.classList.remove('emergency-row'); // Remove the class if the condition is no longer met
            }
        });
    }

    const observerForGrid = new MutationObserver(() => {
        applyHoverEffect();
        applyStatusCellStyle();
        highlightEmergencyRows(); // Call highlightEmergencyRows on every DOM change
    });

    const gridBodyViewport = document.querySelector('.ag-body-viewport'); // Observe the grid body viewport
    if (gridBodyViewport) {
        observerForGrid.observe(gridBodyViewport, { childList: true, subtree: false }); // subtree should be false here as we are observing direct children (rows)
    } else {
        console.warn("AG Grid body viewport not found. Falling back to body observer.");
        observerForGrid.observe(document.body, { childList: true, subtree: true });
    }

    window.addEventListener('load', () => {
        applyHoverEffect();
        applyStatusCellStyle();
        highlightEmergencyRows(); // Initial call to highlight emergency rows
    });

    // Set the dropdown value for pagination to 100
    function setDropdownValue() {
        const dropdown = document.getElementById("dropdownPaginationPageSize");
        if (dropdown && dropdown.value !== "100") {
            dropdown.value = "100"; // Set the value to "100"

            // Trigger the 'change' event
            const event = new Event('change', { bubbles: true });
            dropdown.dispatchEvent(event);

            console.log("Dropdown value set to 100");
        }
    }

    // Observe changes in the DOM for the dropdown
    function observeDOMForDropdown() {
        const observer = new MutationObserver(() => {
            setDropdownValue(); // Check and set the dropdown value when changes are detected
        });

        // Observe the entire document for changes
        observer.observe(document.body, {
            childList: true,
            subtree: true,
        });

        console.log("MutationObserver is active for dropdown");
    }

    window.addEventListener('load', () => {
        setDropdownValue(); // Initial check
        observeDOMForDropdown(); // Start observing for dynamic changes
    });

})();