start:utils:cockpit:p1:cpu:priority
Table of Contents
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, "&") .replace(/</g, "<") .replace(/>/g, ">") .replace(/"/g, """); } function escapeAttr(str) { return String(str).replace(/[^a-zA-Z0-9_-]/g, "_"); }
start/utils/cockpit/p1/cpu/priority.txt · Last modified: by admin_wiki
