Fix Remediate integration in QueuePanel on Reporting Page
- Add remediationModalItem state to QueuePanel - Render RemediationModal from QueuePanel for notes access - Add Remediate color to wfColor mapping in renderQueueItem - Add Remediate option to SelectionToolbar workflow type buttons The Notes button and Remediate workflow option were only added to the standalone IvantiTodoQueuePage but not the QueuePanel slide-out on the Reporting Page, which is the primary interface for queue interaction.
This commit is contained in:
@@ -9,6 +9,7 @@ import CveTooltip from '../CveTooltip';
|
||||
import CardOwnerTooltip from '../CardOwnerTooltip';
|
||||
import CardDetailModal from '../CardDetailModal';
|
||||
import RedirectModal from '../RedirectModal';
|
||||
import RemediationModal from '../RemediationModal';
|
||||
import AtlasBadge from '../AtlasBadge';
|
||||
import LoaderModal from '../LoaderModal';
|
||||
import CardActionModal from '../CardActionModal';
|
||||
@@ -1558,6 +1559,9 @@ function QueuePanel({ open, items, onClose, onUpdate, onDelete, onDeleteMany, on
|
||||
const [createJiraOpen, setCreateJiraOpen] = useState(false);
|
||||
const [createJiraForm, setCreateJiraForm] = useState({ summary: '', cve_id: '', vendor: '', source_context: 'ivanti_queue', description: '', project_key: '', issue_type: '' });
|
||||
const [createJiraError, setCreateJiraError] = useState(null);
|
||||
|
||||
// Remediation Modal state
|
||||
const [remediationModalItem, setRemediationModalItem] = useState(null);
|
||||
const [createJiraSaving, setCreateJiraSaving] = useState(false);
|
||||
const [createJiraSummaryError, setCreateJiraSummaryError] = useState(null);
|
||||
|
||||
@@ -1819,6 +1823,7 @@ function QueuePanel({ open, items, onClose, onUpdate, onDelete, onDeleteMany, on
|
||||
: item.workflow_type === 'Archer' ? { col: '#0EA5E9', rgb: '14,165,233' }
|
||||
: item.workflow_type === 'GRANITE' ? { col: '#A1887F', rgb: '161,136,127' }
|
||||
: item.workflow_type === 'DECOM' ? { col: '#EF4444', rgb: '239,68,68' }
|
||||
: item.workflow_type === 'Remediate' ? { col: '#A855F7', rgb: '168,85,247' }
|
||||
: { col: '#10B981', rgb: '16,185,129' };
|
||||
const cves = item.cves || [];
|
||||
const cveDisplay = cves.length > 0
|
||||
@@ -2010,6 +2015,53 @@ function QueuePanel({ open, items, onClose, onUpdate, onDelete, onDeleteMany, on
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* Remediation Notes button — Remediate items only */}
|
||||
{item.workflow_type === 'Remediate' && (
|
||||
<button
|
||||
onClick={() => setRemediationModalItem(item)}
|
||||
style={{
|
||||
background: 'rgba(168, 85, 247, 0.08)',
|
||||
border: '1px solid rgba(168, 85, 247, 0.25)',
|
||||
borderRadius: '0.2rem',
|
||||
padding: '0.15rem 0.35rem',
|
||||
cursor: 'pointer',
|
||||
display: 'inline-flex',
|
||||
alignItems: 'center',
|
||||
gap: '0.2rem',
|
||||
color: '#C084FC',
|
||||
fontFamily: 'monospace',
|
||||
fontSize: '0.55rem',
|
||||
fontWeight: '700',
|
||||
textTransform: 'uppercase',
|
||||
letterSpacing: '0.04em',
|
||||
flexShrink: 0,
|
||||
transition: 'all 0.12s',
|
||||
position: 'relative',
|
||||
}}
|
||||
onMouseEnter={(e) => { e.currentTarget.style.background = 'rgba(168, 85, 247, 0.18)'; e.currentTarget.style.borderColor = 'rgba(168, 85, 247, 0.45)'; }}
|
||||
onMouseLeave={(e) => { e.currentTarget.style.background = 'rgba(168, 85, 247, 0.08)'; e.currentTarget.style.borderColor = 'rgba(168, 85, 247, 0.25)'; }}
|
||||
title="View remediation notes"
|
||||
>
|
||||
<FileText style={{ width: '10px', height: '10px' }} />
|
||||
Notes
|
||||
{(item.remediation_notes_count || 0) > 0 && (
|
||||
<span style={{
|
||||
fontFamily: 'monospace',
|
||||
fontSize: '0.5rem',
|
||||
fontWeight: 700,
|
||||
color: '#A855F7',
|
||||
background: 'rgba(168, 85, 247, 0.15)',
|
||||
border: '1px solid rgba(168, 85, 247, 0.3)',
|
||||
borderRadius: '999px',
|
||||
padding: '0 0.25rem',
|
||||
marginLeft: '0.1rem',
|
||||
}}>
|
||||
{item.remediation_notes_count > 99 ? '99+' : item.remediation_notes_count}
|
||||
</span>
|
||||
)}
|
||||
</button>
|
||||
)}
|
||||
|
||||
{/* Redirect button — available on all items */}
|
||||
{canWrite && (
|
||||
<button
|
||||
@@ -2959,6 +3011,17 @@ function QueuePanel({ open, items, onClose, onUpdate, onDelete, onDeleteMany, on
|
||||
/>
|
||||
)}
|
||||
|
||||
{/* Remediation Notes modal */}
|
||||
{remediationModalItem && (
|
||||
<RemediationModal
|
||||
item={remediationModalItem}
|
||||
onClose={() => setRemediationModalItem(null)}
|
||||
onNoteAdded={() => {
|
||||
if (onQueueRefresh) onQueueRefresh();
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
|
||||
{/* Create Jira Ticket modal */}
|
||||
{createJiraOpen && (
|
||||
<div style={{ position: 'fixed', inset: 0, zIndex: 10100, display: 'flex', alignItems: 'center', justifyContent: 'center' }}>
|
||||
@@ -3236,8 +3299,11 @@ function AttachmentSourcePicker({ files, onFilesChange, libraryDocs, onLibraryDo
|
||||
const debounceRef = useRef(null);
|
||||
|
||||
// Format file size helper
|
||||
const formatSize = (bytes) => {
|
||||
const n = Number(bytes);
|
||||
const formatSize = (val) => {
|
||||
if (!val && val !== 0) return '0 B';
|
||||
// If already a formatted string (e.g. "12.34 KB"), return as-is
|
||||
if (typeof val === 'string' && /[A-Za-z]/.test(val)) return val;
|
||||
const n = Number(val);
|
||||
if (isNaN(n) || n < 0) return '0 B';
|
||||
if (n < 1024) return n + ' B';
|
||||
if (n < 1024 * 1024) return (n / 1024).toFixed(1) + ' KB';
|
||||
@@ -5009,6 +5075,7 @@ function SelectionToolbar({ count, workflowType, vendor, submitting, error, onWo
|
||||
{ type: 'CARD', color: '#10B981', rgb: '16,185,129' },
|
||||
{ type: 'GRANITE', color: '#A1887F', rgb: '161,136,127' },
|
||||
{ type: 'DECOM', color: '#EF4444', rgb: '239,68,68' },
|
||||
{ type: 'Remediate', color: '#A855F7', rgb: '168,85,247' },
|
||||
].map(({ type, color, rgb }) => {
|
||||
const active = workflowType === type;
|
||||
return (
|
||||
|
||||
Reference in New Issue
Block a user