From 3b5dfee2352dcd576ed320de3d348119e030e2f9 Mon Sep 17 00:00:00 2001 From: Jordan Ramos Date: Mon, 8 Jun 2026 14:59:48 -0600 Subject: [PATCH] Append remediation notes to Jira ticket description in QueuePanel - Single-item: openCreateJiraFromQueue fetches notes for Remediate items and pre-fills the description with a Remediation Notes section - Multi-item: ConsolidationModal fetches notes for all Remediate items and appends them via appendRemediationNotes utility Previously notes were only integrated in IvantiTodoQueuePage.js but the actual Jira creation flow users interact with is in ReportingPage.js QueuePanel and ConsolidationModal. --- frontend/src/components/ConsolidationModal.js | 25 ++++++++++++++++++- .../src/components/pages/ReportingPage.js | 24 ++++++++++++++++-- 2 files changed, 46 insertions(+), 3 deletions(-) diff --git a/frontend/src/components/ConsolidationModal.js b/frontend/src/components/ConsolidationModal.js index fd2cf28..6012225 100644 --- a/frontend/src/components/ConsolidationModal.js +++ b/frontend/src/components/ConsolidationModal.js @@ -5,6 +5,7 @@ import { generateConsolidatedDescription, extractFirstCve, extractCommonVendor, + appendRemediationNotes, } from '../utils/jiraConsolidation'; const API_BASE = process.env.REACT_APP_API_BASE || 'http://localhost:3001/api'; @@ -285,9 +286,31 @@ export default function ConsolidationModal({ items, onClose, onSuccess }) { useEffect(() => { if (items.length >= 2) { setSummary(generateConsolidatedSummary(items)); - setDescription(generateConsolidatedDescription(items)); setCveId(extractFirstCve(items)); setVendor(extractCommonVendor(items)); + + // Build description, appending remediation notes for Remediate items + const baseDescription = generateConsolidatedDescription(items); + const remediateItems = items.filter(i => i.workflow_type === 'Remediate'); + if (remediateItems.length > 0) { + Promise.all( + remediateItems.map(item => + fetch(`${API_BASE}/ivanti/todo-queue/${item.id}/notes`, { credentials: 'include' }) + .then(r => r.ok ? r.json() : []) + .catch(() => []) + ) + ).then(results => { + const notesMap = {}; + remediateItems.forEach((item, idx) => { + if (results[idx] && results[idx].length > 0) { + notesMap[item.id] = results[idx]; + } + }); + setDescription(appendRemediationNotes(baseDescription, notesMap)); + }); + } else { + setDescription(baseDescription); + } } }, [items]); diff --git a/frontend/src/components/pages/ReportingPage.js b/frontend/src/components/pages/ReportingPage.js index 1a9c0b3..c2cbd7e 100644 --- a/frontend/src/components/pages/ReportingPage.js +++ b/frontend/src/components/pages/ReportingPage.js @@ -1759,7 +1759,7 @@ function QueuePanel({ open, items, onClose, onUpdate, onDelete, onDeleteMany, on }; // Open Create Jira modal pre-populated from a queue item - const openCreateJiraFromQueue = (item) => { + const openCreateJiraFromQueue = async (item) => { // Parse cves_json — it may be a JSON string or already an array let cves = []; if (item.cves_json) { @@ -1769,12 +1769,32 @@ function QueuePanel({ open, items, onClose, onUpdate, onDelete, onDeleteMany, on } const firstCve = (Array.isArray(cves) && cves.length > 0) ? cves[0] : ''; const summary = (item.finding_title || '').slice(0, 255); + + // Build description — include remediation notes for Remediate items + let description = ''; + if (item.workflow_type === 'Remediate') { + try { + const notesRes = await fetch(`${API_BASE}/ivanti/todo-queue/${item.id}/notes`, { credentials: 'include' }); + if (notesRes.ok) { + const notes = await notesRes.json(); + if (notes.length > 0) { + const sorted = [...notes].sort((a, b) => new Date(a.created_at) - new Date(b.created_at)); + description = '== Remediation Notes ==\n'; + for (const note of sorted) { + const date = note.created_at ? note.created_at.slice(0, 10) : 'Unknown'; + description += `[${date}] ${note.username}: ${note.note_text}\n`; + } + } + } + } catch (_) { /* best-effort */ } + } + setCreateJiraForm({ summary, cve_id: firstCve, vendor: item.vendor || '', source_context: 'ivanti_queue', - description: '', + description, project_key: '', issue_type: '', });