window.showUpsell = function(featureName) {
const featureNameEl = document.getElementById('upsellFeatureName');
const modalEl = document.getElementById('upsellModal');
if (featureNameEl && modalEl) {
featureNameEl.innerText = featureName;
modalEl.style.display = 'flex';
} else {
alert("This feature (" + featureName + ") is available in RiskRancher Pro!");
}
};
window.renderMarkdown = function(text) {
if (!text) return "No description provided.";
let html = text.replace(/!\[.*?\]\((.*?)\)/g, '
');
html = html.replace(/\n/g, '
');
return html;
};
window.updateDrawerPreview = function() {
const rawDesc = document.getElementById('drawerDescEdit').value;
document.getElementById('drawerDescPreview').innerHTML = renderMarkdown(rawDesc);
};
window.openDrawer = function(id, title, asset, severity) {
document.getElementById('drawerTicketID').value = id;
document.getElementById('drawerTitle').innerText = title;
document.getElementById('drawerAsset').innerText = asset;
const badge = document.getElementById('drawerBadge');
badge.innerText = severity;
badge.className = `badge ${severity.toLowerCase()}`;
document.getElementById('drawerSeverity').value = severity;
document.getElementById('drawerComment').value = "";
const rawDesc = document.getElementById('desc-' + id) ? document.getElementById('desc-' + id).value : "";
const rawRem = document.getElementById('rem-' + id) ? document.getElementById('rem-' + id).value : "";
const rawEv = document.getElementById('ev-' + id) ? document.getElementById('ev-' + id).value : "";
const status = document.getElementById('status-' + id) ? document.getElementById('status-' + id).value : "";
const rawComment = document.getElementById('comment-' + id) ? document.getElementById('comment-' + id).value : "";
const assignee = document.getElementById('assignee-' + id) ? document.getElementById('assignee-' + id).value : "";
document.getElementById('drawerDescEdit').value = rawDesc;
document.getElementById('drawerRemEdit').value = rawRem;
const drawerAssignee = document.getElementById('drawerAssignee');
if (drawerAssignee) {
drawerAssignee.value = (assignee === "Unassigned") ? "" : assignee;
}
const evBlock = document.getElementById('drawerEvidenceBlock');
const evText = document.getElementById('drawerEvidenceText');
if (evBlock && evText) {
if (rawEv && rawEv.trim() !== "") {
evText.innerText = rawEv;
evBlock.style.display = "block";
} else {
evBlock.style.display = "none";
evText.innerText = "";
}
}
const retBlock = document.getElementById('drawerReturnedBlock');
const retText = document.getElementById('drawerReturnedText');
if (retBlock && retText) {
if (status === 'Returned to Security' && rawComment) {
retText.innerText = rawComment;
retBlock.style.display = "block";
} else {
retBlock.style.display = "none";
retText.innerText = "";
}
}
const standardActions = document.getElementById('drawerStandardActions');
const editControls = document.getElementById('drawerEditControls');
if (window.CurrentTab === 'archives') {
if(standardActions) standardActions.style.display = 'none';
if(editControls) editControls.style.display = 'none';
} else {
if(standardActions) standardActions.style.display = 'flex';
if(editControls) editControls.style.display = 'block';
}
updateDrawerPreview();
document.getElementById('ticketDrawer').style.width = '600px';
document.getElementById('ticketDrawer').classList.add('open');
document.getElementById('drawerOverlay').style.display = 'block';
};
window.closeDrawer = function() {
document.getElementById('ticketDrawer').classList.remove('open');
document.getElementById('drawerOverlay').style.display = 'none';
};
window.openNewTicketModal = function() {
// Clear out old values just in case
document.getElementById('newTicketTitle').value = '';
document.getElementById('newTicketAsset').value = '';
document.getElementById('newTicketDesc').value = '';
document.getElementById('newTicketSeverity').value = 'High';
document.getElementById('newTicketModal').style.display = 'flex';
};
window.submitNewTicket = async function() {
const title = document.getElementById('newTicketTitle').value.trim();
const asset = document.getElementById('newTicketAsset').value.trim();
const severity = document.getElementById('newTicketSeverity').value;
const desc = document.getElementById('newTicketDesc').value.trim();
if (!title || !asset) {
return alert("Title and Asset Identifier are required!");
}
const payload = {
title: title,
asset_identifier: asset,
severity: severity,
description: desc,
source: "Manual",
status: "Waiting to be Triaged"
};
try {
const res = await fetch('/api/tickets', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(payload)
});
if (res.ok) {
window.location.reload();
} else {
alert("Failed to create ticket.");
}
} catch (err) {
alert("Network error.");
}
};
window.toggleAssetGroup = function(safeAsset) {
document.querySelectorAll(`.group-${safeAsset}`).forEach(r => {
r.style.display = r.style.display === "none" ? "table-row" : "none";
});
};
function initializeAssetTree() {
const tbody = document.getElementById("ticketTableBody");
if (!tbody) return;
const rows = Array.from(tbody.querySelectorAll("tr.ticket-row"));
if (rows.length === 0) {
document.getElementById("mainTableHeader").style.display = "table-header-group";
tbody.innerHTML = `