From 75ac8c823a6bb40378a1646d0f1b9b44d8c28c3a Mon Sep 17 00:00:00 2001 From: jramos Date: Mon, 13 Apr 2026 14:25:14 -0600 Subject: [PATCH] feat: show finding IDs in history, display Ivanti reviewer notes (rework/approval feedback) in history tab --- backend/routes/ivantiFpWorkflow.js | 37 +++++++++++++++++++ .../src/components/pages/ReportingPage.js | 34 +++++++++++++++-- 2 files changed, 68 insertions(+), 3 deletions(-) diff --git a/backend/routes/ivantiFpWorkflow.js b/backend/routes/ivantiFpWorkflow.js index 569b780..b8aaeec 100644 --- a/backend/routes/ivantiFpWorkflow.js +++ b/backend/routes/ivantiFpWorkflow.js @@ -560,6 +560,43 @@ function createIvantiFpWorkflowRouter(db, requireAuth) { for (const sub of submissions) { sub.history = historyMap[sub.id] || []; } + + // Enrich submissions with Ivanti reviewer notes (rework/approval feedback) + const apiKey = process.env.IVANTI_API_KEY; + const clientId = process.env.IVANTI_CLIENT_ID || '1550'; + const skipTls = process.env.IVANTI_SKIP_TLS === 'true'; + + if (apiKey) { + try { + // Batch search by all workflow names + for (const sub of submissions) { + if (!sub.workflow_name) continue; + const searchUrl = `/client/${encodeURIComponent(clientId)}/workflowBatch/search`; + const searchBody = { + filters: [{ field: 'name', exclusive: false, operator: 'EXACT', value: sub.workflow_name }], + projection: 'internal', + sort: [{ field: 'created', direction: 'DESC' }], + page: 0, size: 1 + }; + const result = await ivantiPost(searchUrl, searchBody, apiKey, skipTls); + if (result.status === 200) { + const data = JSON.parse(result.body); + const batches = data._embedded?.workflowBatches || data._embedded?.workflowBatch || []; + const batch = batches[0]; + if (batch) { + sub.ivanti_rework_note = batch.reworkNote || null; + sub.ivanti_approval_note = batch.approvalNote || null; + sub.ivanti_current_state_notes = batch.currentStateUserNotes || null; + sub.ivanti_previous_state_notes = batch.previousStateUserNotes || null; + sub.ivanti_current_state = batch.currentState || null; + } + } + } + } catch (e) { + console.error('Error enriching submissions with Ivanti notes:', e.message); + // Don't fail the response — notes are supplementary + } + } } else { // No submissions, nothing to do } diff --git a/frontend/src/components/pages/ReportingPage.js b/frontend/src/components/pages/ReportingPage.js index e704429..df92711 100644 --- a/frontend/src/components/pages/ReportingPage.js +++ b/frontend/src/components/pages/ReportingPage.js @@ -2707,6 +2707,21 @@ function FpEditModal({ open, onClose, submission, queueItems, onSuccess }) { {/* History tab */} {activeTab === 'history' && (
+ {/* Ivanti reviewer notes (rework/approval feedback) */} + {(submission.ivanti_rework_note || submission.ivanti_current_state_notes) && ( +
+
+ Ivanti Reviewer Notes +
+
+ {submission.ivanti_rework_note || submission.ivanti_current_state_notes} +
+
+ )} {history.length === 0 ? (
No history entries. @@ -2742,13 +2757,26 @@ function FpEditModal({ open, onClose, submission, queueItems, onSuccess }) {
)} {entry.change_type === 'findings_added' && details.addedFindingIds && ( -
- +{details.addedFindingIds.length} finding(s) +
+
+ +{details.addedFindingIds.length} finding(s): +
+
+ {details.addedFindingIds.map(fid => ( + + {fid} + + ))} +
)} {entry.change_type === 'attachments_added' && details.files && (
- {details.files.length} file(s) uploaded + {details.files.filter(f => f.success).length} of {details.files.length} file(s) uploaded
)}