better docs
Deploy / deploy (push) Successful in 38s

This commit is contained in:
2026-05-08 00:55:47 +02:00
parent 2dd762cc6b
commit f011522848
2 changed files with 56 additions and 4 deletions
+2 -2
View File
@@ -506,7 +506,7 @@ function handleDocuments($method, $id, $db) {
$typeLabels = ['deployment' => 'Deployment', 'attack' => 'Attack', 'incident-report' => 'Incident Report', 'remediation' => 'Remediation', 'exercise' => 'Exercise']; $typeLabels = ['deployment' => 'Deployment', 'attack' => 'Attack', 'incident-report' => 'Incident Report', 'remediation' => 'Remediation', 'exercise' => 'Exercise'];
$typeLabel = $typeLabels[$docType] ?? ucfirst($docType); $typeLabel = $typeLabels[$docType] ?? ucfirst($docType);
$eventTitle = $typeLabel . ': ' . $data['title']; $eventTitle = $typeLabel . ': ' . $data['title'];
$eventDesc = $username . ' created document "' . $data['title'] . '" (' . $typeLabel . ')'; $eventDesc = $username . ' created [doc:' . $docId . ']' . $data['title'] . '[/doc] (' . $typeLabel . ')';
$stmt2 = $db->prepare(" $stmt2 = $db->prepare("
INSERT INTO events (team_id, title, description, severity, event_type, occurred_at) INSERT INTO events (team_id, title, description, severity, event_type, occurred_at)
VALUES (?, ?, ?, 'info', 'document', ?) VALUES (?, ?, ?, 'info', 'document', ?)
@@ -538,7 +538,7 @@ function handleDocuments($method, $id, $db) {
$typeLabels = ['deployment' => 'Deployment', 'attack' => 'Attack', 'incident-report' => 'Incident Report', 'remediation' => 'Remediation', 'exercise' => 'Exercise']; $typeLabels = ['deployment' => 'Deployment', 'attack' => 'Attack', 'incident-report' => 'Incident Report', 'remediation' => 'Remediation', 'exercise' => 'Exercise'];
$typeLabel = $typeLabels[$docType] ?? ucfirst($docType); $typeLabel = $typeLabels[$docType] ?? ucfirst($docType);
$eventTitle = 'Updated ' . $typeLabel . ': ' . $docTitle; $eventTitle = 'Updated ' . $typeLabel . ': ' . $docTitle;
$eventDesc = $username . ' updated document "' . $docTitle . '" (' . $typeLabel . ')'; $eventDesc = $username . ' updated [doc:' . $id . ']' . $docTitle . '[/doc] (' . $typeLabel . ')';
$stmt2 = $db->prepare(" $stmt2 = $db->prepare("
INSERT INTO events (team_id, title, description, severity, event_type, occurred_at) INSERT INTO events (team_id, title, description, severity, event_type, occurred_at)
VALUES (?, ?, ?, 'info', 'document', ?) VALUES (?, ?, ?, 'info', 'document', ?)
+54 -2
View File
@@ -268,7 +268,7 @@ function renderTimeline() {
<small class="event-meta">${date}</small> <small class="event-meta">${date}</small>
</div> </div>
<h6 class="event-title mt-1 mb-1">${esc(e.title)}</h6> <h6 class="event-title mt-1 mb-1">${esc(e.title)}</h6>
${e.description ? '<p class="mb-1 small text-secondary">' + esc(e.description) + '</p>' : ''} ${e.description ? '<p class="mb-1 small text-secondary">' + renderDocLinks(e.description) + '</p>' : ''}
<div class="text-end"> <div class="text-end">
<button class="btn btn-outline-danger btn-sm py-0 px-1" onclick="deleteEvent(${e.id}, this)" title="Delete event" style="font-size:.7rem;"><i class="fas fa-trash"></i></button> <button class="btn btn-outline-danger btn-sm py-0 px-1" onclick="deleteEvent(${e.id}, this)" title="Delete event" style="font-size:.7rem;"><i class="fas fa-trash"></i></button>
</div> </div>
@@ -286,6 +286,58 @@ function renderTimeline() {
}).join(''); }).join('');
} }
function renderDocLinks(text) {
const parts = text.split(/(\[doc:\d+\].*?\[\/doc\])/g);
return parts.map(p => {
const m = p.match(/\[doc:(\d+)\](.*?)\[\/doc\]/);
if (m) {
return `<a href="#" class="doc-link" onclick="event.preventDefault();openDocument(${m[1]})" style="color:var(--neptune-accent);text-decoration:underline;cursor:pointer;">${esc(m[2])}</a>`;
}
return esc(p);
}).join('');
}
function openDocument(id) {
const tab = document.getElementById('documents-tab');
if (tab) tab.click();
setTimeout(() => {
const container = document.getElementById('documentContainer');
if (!container) return;
const cards = container.querySelectorAll('.doc-card');
cards.forEach(c => {
c.style.transition = 'box-shadow .3s, border-color .3s';
c.style.boxShadow = '';
c.style.borderColor = '';
});
const target = container.querySelector(`[data-doc-id="${id}"]`);
if (target) {
target.scrollIntoView({ behavior: 'smooth', block: 'center' });
target.style.boxShadow = '0 0 20px rgba(59,130,246,.5)';
target.style.borderColor = 'var(--neptune-accent)';
setTimeout(() => {
target.style.boxShadow = '';
target.style.borderColor = '';
}, 3000);
} else {
loadDocuments().then(() => {
setTimeout(() => {
const el = document.getElementById('documentContainer').querySelector(`[data-doc-id="${id}"]`);
if (el) {
el.scrollIntoView({ behavior: 'smooth', block: 'center' });
el.style.boxShadow = '0 0 20px rgba(59,130,246,.5)';
el.style.borderColor = 'var(--neptune-accent)';
setTimeout(() => { el.style.boxShadow = ''; el.style.borderColor = ''; }, 3000);
}
}, 100);
});
}
const filter = document.getElementById('searchDocs');
if (filter) filter.value = '';
document.getElementById('docTeamFilter').value = '';
document.getElementById('docTypeFilter').value = '';
}, 300);
}
function renderComments(event) { function renderComments(event) {
if (!event.comments || !event.comments.length) return '<div class="text-secondary small py-1"><i class="fas fa-comment me-1"></i>No comments yet</div>'; if (!event.comments || !event.comments.length) return '<div class="text-secondary small py-1"><i class="fas fa-comment me-1"></i>No comments yet</div>';
return event.comments.map(c => ` return event.comments.map(c => `
@@ -1030,7 +1082,7 @@ function renderDocuments() {
const contentPreview = d.content ? d.content.substring(0, 150) + (d.content.length > 150 ? '...' : '') : ''; const contentPreview = d.content ? d.content.substring(0, 150) + (d.content.length > 150 ? '...' : '') : '';
return ` return `
<div class="col-md-6 col-lg-4 mb-3"> <div class="col-md-6 col-lg-4 mb-3">
<div class="card bg-dark border-secondary h-100 doc-card"> <div class="card bg-dark border-secondary h-100 doc-card" data-doc-id="${d.id}">
<div class="card-header border-secondary py-2 d-flex justify-content-between align-items-center"> <div class="card-header border-secondary py-2 d-flex justify-content-between align-items-center">
<div> <div>
<span class="badge me-1" style="background:${meta.color}20;color:${meta.color};border:1px solid ${meta.color}40;"> <span class="badge me-1" style="background:${meta.color}20;color:${meta.color};border:1px solid ${meta.color}40;">