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 CardOwnerTooltip from '../CardOwnerTooltip';
|
||||||
import CardDetailModal from '../CardDetailModal';
|
import CardDetailModal from '../CardDetailModal';
|
||||||
import RedirectModal from '../RedirectModal';
|
import RedirectModal from '../RedirectModal';
|
||||||
|
import RemediationModal from '../RemediationModal';
|
||||||
import AtlasBadge from '../AtlasBadge';
|
import AtlasBadge from '../AtlasBadge';
|
||||||
import LoaderModal from '../LoaderModal';
|
import LoaderModal from '../LoaderModal';
|
||||||
import CardActionModal from '../CardActionModal';
|
import CardActionModal from '../CardActionModal';
|
||||||
@@ -1558,6 +1559,9 @@ function QueuePanel({ open, items, onClose, onUpdate, onDelete, onDeleteMany, on
|
|||||||
const [createJiraOpen, setCreateJiraOpen] = useState(false);
|
const [createJiraOpen, setCreateJiraOpen] = useState(false);
|
||||||
const [createJiraForm, setCreateJiraForm] = useState({ summary: '', cve_id: '', vendor: '', source_context: 'ivanti_queue', description: '', project_key: '', issue_type: '' });
|
const [createJiraForm, setCreateJiraForm] = useState({ summary: '', cve_id: '', vendor: '', source_context: 'ivanti_queue', description: '', project_key: '', issue_type: '' });
|
||||||
const [createJiraError, setCreateJiraError] = useState(null);
|
const [createJiraError, setCreateJiraError] = useState(null);
|
||||||
|
|
||||||
|
// Remediation Modal state
|
||||||
|
const [remediationModalItem, setRemediationModalItem] = useState(null);
|
||||||
const [createJiraSaving, setCreateJiraSaving] = useState(false);
|
const [createJiraSaving, setCreateJiraSaving] = useState(false);
|
||||||
const [createJiraSummaryError, setCreateJiraSummaryError] = useState(null);
|
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 === 'Archer' ? { col: '#0EA5E9', rgb: '14,165,233' }
|
||||||
: item.workflow_type === 'GRANITE' ? { col: '#A1887F', rgb: '161,136,127' }
|
: item.workflow_type === 'GRANITE' ? { col: '#A1887F', rgb: '161,136,127' }
|
||||||
: item.workflow_type === 'DECOM' ? { col: '#EF4444', rgb: '239,68,68' }
|
: 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' };
|
: { col: '#10B981', rgb: '16,185,129' };
|
||||||
const cves = item.cves || [];
|
const cves = item.cves || [];
|
||||||
const cveDisplay = cves.length > 0
|
const cveDisplay = cves.length > 0
|
||||||
@@ -2010,6 +2015,53 @@ function QueuePanel({ open, items, onClose, onUpdate, onDelete, onDeleteMany, on
|
|||||||
</div>
|
</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 */}
|
{/* Redirect button — available on all items */}
|
||||||
{canWrite && (
|
{canWrite && (
|
||||||
<button
|
<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 */}
|
{/* Create Jira Ticket modal */}
|
||||||
{createJiraOpen && (
|
{createJiraOpen && (
|
||||||
<div style={{ position: 'fixed', inset: 0, zIndex: 10100, display: 'flex', alignItems: 'center', justifyContent: 'center' }}>
|
<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);
|
const debounceRef = useRef(null);
|
||||||
|
|
||||||
// Format file size helper
|
// Format file size helper
|
||||||
const formatSize = (bytes) => {
|
const formatSize = (val) => {
|
||||||
const n = Number(bytes);
|
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 (isNaN(n) || n < 0) return '0 B';
|
||||||
if (n < 1024) return n + ' B';
|
if (n < 1024) return n + ' B';
|
||||||
if (n < 1024 * 1024) return (n / 1024).toFixed(1) + ' KB';
|
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: 'CARD', color: '#10B981', rgb: '16,185,129' },
|
||||||
{ type: 'GRANITE', color: '#A1887F', rgb: '161,136,127' },
|
{ type: 'GRANITE', color: '#A1887F', rgb: '161,136,127' },
|
||||||
{ type: 'DECOM', color: '#EF4444', rgb: '239,68,68' },
|
{ type: 'DECOM', color: '#EF4444', rgb: '239,68,68' },
|
||||||
|
{ type: 'Remediate', color: '#A855F7', rgb: '168,85,247' },
|
||||||
].map(({ type, color, rgb }) => {
|
].map(({ type, color, rgb }) => {
|
||||||
const active = workflowType === type;
|
const active = workflowType === type;
|
||||||
return (
|
return (
|
||||||
|
|||||||
Reference in New Issue
Block a user