User Tools

Site Tools


start:utils:cockpit:p1:cpu:priority

Ticket Priority

Le bouton refresh va faire un appel API pour récupérer la liste des priorités qui existent (même celles d'organisations non sélectionnées).

Sélectionner les priorités relevantes (soit en cliquant dans la liste ou en utilisant les boutons de sélection) puis sauvegarder.

Headline

WebPriority.py

WebPriority.py
# WebPriority.py
import PersistentData
import CockpitITSM
 
def init_priority_interface(ui):
    """
    Registers the bridge between Priority.html and Python logic.
    """
 
    def handle_get_ticket_priorities(_, __):
        """Syncs with API then returns ticket priorities from DB, sorted by subType / reference."""
        success = CockpitITSM.update_ticket_priorities()
 
        if not success:
            ui.send_message("priority_response", {
                "success": False,
                "message": "Failed to refresh ticket priorities. Check API configuration."
            })
            return
 
        priorities = PersistentData.get_ticket_priorities()
        ui.send_message("priority_data", {"priorities": priorities})
 
    def handle_save_ticket_priorities(_, data):
        """Persists the selected state for each ticket priority."""
        try:
            priorities = data.get("priorities", [])
            for p in priorities:
                PersistentData.db.update(
                    "objects",
                    {"selected": p["selected"]},
                    condition=f"id = {p['id']} AND subType = '{p['subType']}'"
                )
            print(f"DEBUG: Saved selection for {len(priorities)} ticket priorities.")
            ui.send_message("priority_response", {
                "success": True,
                "message": f"Selection saved ({len(priorities)} priorities)."
            })
        except Exception as e:
            print(f"ERROR saving ticket priorities: {str(e)}")
            ui.send_message("priority_response", {
                "success": False,
                "message": f"Save error: {str(e)}"
            })
 
    # Registering the handlers
    ui.on_message("get_ticket_priorities",  handle_get_ticket_priorities)
    ui.on_message("save_ticket_priorities", handle_save_ticket_priorities)

Priority.html

Priority.html
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>P1 Notifications 4 Cockpit ITSM - Ticket Priority</title>
    <link rel="stylesheet" href="style.css">
    <link rel="icon" type="image/x-icon" href="img/favicon.ico">
    <style>
        .org-list {
            margin: 1.2rem 0;
            max-height: 320px;
            overflow-y: auto;
            border: 1px solid #333;
            border-radius: 4px;
            background-color: #2a2a2a;
        }
        .org-list-empty {
            padding: 1.2rem;
            text-align: center;
            color: #666;
            font-size: 0.85rem;
        }
        .org-item {
            display: flex;
            align-items: center;
            gap: 10px;
            padding: 0.65rem 1rem;
            border-bottom: 1px solid #333;
            cursor: pointer;
            transition: background-color 0.15s;
        }
        .org-item:last-child { border-bottom: none; }
        .org-item:hover { background-color: #333; }
        .org-item input[type="checkbox"] {
            width: 16px;
            height: 16px;
            accent-color: #00aaff;
            cursor: pointer;
            flex-shrink: 0;
        }
        .org-item label {
            cursor: pointer;
            font-size: 0.9rem;
            color: #e0e0e0;
            flex: 1;
        }
        .selection-group {
            display: flex;
            gap: 8px;
            flex-wrap: wrap;
            margin-bottom: 1rem;
        }
        .selection-group button {
            flex: 1;
            padding: 0.5rem 0.4rem;
            font-size: 0.78rem;
        }
    </style>
</head>
<body>
    <div class="container">
        <header>
            <h1>
                <img src="img/traffic-light-orange.svg" alt="" class="icon-api-svg">
                Ticket Priority
            </h1>
        </header>
 
        <div class="button-group" style="margin-bottom: 1.2rem;">
            <button id="btnRefresh" class="btn-secondary" onclick="refreshPriorities()">
                <img src="img/cloud-download.svg" alt="" class="btn-icon">Refresh
            </button>
        </div>
 
        <div id="priorityList" class="org-list">
            <div class="org-list-empty">Click Refresh to load ticket priorities.</div>
        </div>
 
        <div class="selection-group">
            <button class="btn-secondary" onclick="selectAll()"><img src="img/select-all.svg" alt="" class="btn-icon">Select All</button>
            <button class="btn-secondary" onclick="invertSelection()"><img src="img/select-inverse.svg" alt="" class="btn-icon">Invert</button>
            <button class="btn-secondary" onclick="selectNone()"><img src="img/select-none.svg" alt="" class="btn-icon">Select None</button>
        </div>
 
        <div class="button-group">
            <button id="btnSave" class="btn-primary" onclick="saveSelection()">
                <img src="img/save.svg" alt="" class="btn-icon">Save
            </button>
        </div>
 
        <div id="statusMessage" class="status-message"></div>
 
        <div class="navigation-group" style="margin-top: 1rem; border-top: 1px solid #333; padding-top: 1rem; text-align: center;">
            <a href="index.html" class="btn-secondary" style="display: flex; align-items: center; justify-content: center; gap: 10px; width: 100%; text-decoration: none; padding: 0.8rem; border-radius: 4px; font-weight: bold; box-sizing: border-box;">
                <img src="img/home.svg" alt="Home" style="width: 20px; height: 20px; filter: invert(1);">Back to Home
            </a>
        </div>
    </div>
 
    <script src="libs/socket.io.min.js"></script>
    <script src="app_priority.js"></script>
</body>
</html>

app_priority.js

app_priority.js
// app_priority.js
const socket = io();
 
// ── Socket events ─────────────────────────────────────────────────────────────
 
socket.on("connect", () => {
    console.log("Connected to server");
    refreshPriorities();
});
 
socket.on("connect_error", (err) => {
    console.error("Connection error:", err);
    setStatus("Connection error. Please reload.", false);
});
 
socket.on("priority_data", function(data) {
    renderPriorityList(data.priorities || []);
    setStatus("", null);
    setRefreshEnabled(true);
});
 
socket.on("priority_response", function(data) {
    setStatus(data.message, data.success);
    setRefreshEnabled(true);
});
 
// ── Actions ───────────────────────────────────────────────────────────────────
 
function refreshPriorities() {
    setStatus("Loading ticket priorities...", null);
    setRefreshEnabled(false);
    socket.emit("get_ticket_priorities", {});
}
 
function saveSelection() {
    const checkboxes = document.querySelectorAll(".priority-checkbox");
    const selected = Array.from(checkboxes).map(cb => ({
        id:      parseInt(cb.dataset.id),
        subType: cb.dataset.subtype,
        selected: cb.checked ? 1 : 0
    }));
 
    if (selected.length === 0) {
        setStatus("No priorities to save.", false);
        return;
    }
 
    setStatus("Saving...", null);
    socket.emit("save_ticket_priorities", { priorities: selected });
}
 
function selectAll() {
    document.querySelectorAll(".priority-checkbox").forEach(cb => cb.checked = true);
}
 
function selectNone() {
    document.querySelectorAll(".priority-checkbox").forEach(cb => cb.checked = false);
}
 
function invertSelection() {
    document.querySelectorAll(".priority-checkbox").forEach(cb => cb.checked = !cb.checked);
}
 
// ── Rendering ─────────────────────────────────────────────────────────────────
 
function renderPriorityList(priorities) {
    const container = document.getElementById("priorityList");
 
    if (priorities.length === 0) {
        container.innerHTML = '<div class="org-list-empty">No ticket priorities found.</div>';
        return;
    }
 
    container.innerHTML = priorities.map(p => `
        <div class="org-item" onclick="toggleCheckbox('priority_${p.id}_${escapeAttr(p.subType)}')">
            <input
                type="checkbox"
                class="priority-checkbox"
                id="priority_${p.id}_${escapeAttr(p.subType)}"
                data-id="${p.id}"
                data-subtype="${escapeAttr(p.subType)}"
                ${p.selected ? "checked" : ""}
                onclick="event.stopPropagation()"
            >
            <label for="priority_${p.id}_${escapeAttr(p.subType)}">${escapeHtml(p.subType)} / ${escapeHtml(p.reference)}</label>
        </div>
    `).join("");
}
 
function toggleCheckbox(id) {
    const cb = document.getElementById(id);
    if (cb) cb.checked = !cb.checked;
}
 
// ── Helpers ───────────────────────────────────────────────────────────────────
 
function setStatus(message, success) {
    const el = document.getElementById("statusMessage");
    el.innerText = message;
    if (success === true)       el.style.color = "#4db6ac";
    else if (success === false) el.style.color = "#e57373";
    else                        el.style.color = "#bb86fc";
}
 
function setRefreshEnabled(enabled) {
    document.getElementById("btnRefresh").disabled = !enabled;
}
 
function escapeHtml(str) {
    return String(str)
        .replace(/&/g, "&amp;")
        .replace(/</g, "&lt;")
        .replace(/>/g, "&gt;")
        .replace(/"/g, "&quot;");
}
 
function escapeAttr(str) {
    return String(str).replace(/[^a-zA-Z0-9_-]/g, "_");
}
This website uses cookies. By using the website, you agree with storing cookies on your computer. Also you acknowledge that you have read and understand our Privacy Policy. If you do not agree leave the website.More information about cookies
start/utils/cockpit/p1/cpu/priority.txt · Last modified: by admin_wiki