diff --git a/frontend/src/components/pages/ReportingPage.js b/frontend/src/components/pages/ReportingPage.js
index 3e54e5d..208db42 100644
--- a/frontend/src/components/pages/ReportingPage.js
+++ b/frontend/src/components/pages/ReportingPage.js
@@ -1,6 +1,6 @@
import React, { useState, useEffect, useCallback, useRef, useMemo } from 'react';
import ReactDOM from 'react-dom';
-import { RefreshCw, Loader, AlertCircle, PieChart, ChevronUp, ChevronDown, ChevronRight, ChevronsUpDown, Settings2, GripVertical, Eye, EyeOff, Filter, Download, RotateCcw, Trash2, X, ListTodo, Upload, FileText, Check, AlertTriangle, CornerUpRight, Edit3, Square, CheckSquare, MinusSquare, Search, Database, Plus } from 'lucide-react';
+import { RefreshCw, Loader, AlertCircle, PieChart, ChevronUp, ChevronDown, ChevronRight, ChevronsUpDown, Settings2, GripVertical, Eye, EyeOff, Filter, Download, RotateCcw, Trash2, X, ListTodo, Upload, FileText, Check, AlertTriangle, CornerUpRight, Edit3, Square, CheckSquare, MinusSquare, Search, Database, Plus, FileSpreadsheet } from 'lucide-react';
import * as XLSX from 'xlsx';
import { useAuth } from '../../contexts/AuthContext';
import IvantiCountsChart from './IvantiCountsChart';
@@ -8,6 +8,7 @@ import AnomalyBanner from './AnomalyBanner';
import CveTooltip from '../CveTooltip';
import RedirectModal from '../RedirectModal';
import AtlasBadge from '../AtlasBadge';
+import LoaderModal from '../LoaderModal';
import ConsolidationModal from '../ConsolidationModal';
import AtlasSlideOutPanel from '../AtlasSlideOutPanel';
import AtlasIcon from '../AtlasIcon';
@@ -1537,6 +1538,9 @@ function QueuePanel({ open, items, onClose, onUpdate, onDelete, onDeleteMany, on
const [cardActionLoading, setCardActionLoading] = useState(false);
const [cardActionError, setCardActionError] = useState(null);
+ // Granite Loader Sheet modal state
+ const [showLoaderModal, setShowLoaderModal] = useState(false);
+
// Create Jira modal state
const [createJiraOpen, setCreateJiraOpen] = useState(false);
const [createJiraForm, setCreateJiraForm] = useState({ summary: '', cve_id: '', vendor: '', source_context: 'ivanti_queue', description: '', project_key: '', issue_type: '' });
@@ -2811,6 +2815,33 @@ function QueuePanel({ open, items, onClose, onUpdate, onDelete, onDeleteMany, on
+ Jira ({items.filter(i => selectedIds.has(i.id) && i.status === 'pending').length})
)}
+ {/* Generate Loader Sheet — visible when CARD/GRANITE/DECOM items are selected or as standalone */}
+ {(() => {
+ const selectedCardGranite = items.filter(i => selectedIds.has(i.id) && ['CARD', 'GRANITE', 'DECOM'].includes(i.workflow_type));
+ const hasCardGraniteItems = items.some(i => ['CARD', 'GRANITE', 'DECOM'].includes(i.workflow_type));
+ const isEnabled = selectedCardGranite.length > 0 || hasCardGraniteItems;
+ return isEnabled ? (
+
+ ) : null;
+ })()}
{selectedIds.size > 0 && (
)}
+
+ {/* Granite Loader Sheet Modal */}
+ setShowLoaderModal(false)}
+ initialDevices={showLoaderModal ? (() => {
+ const selected = items.filter(i => selectedIds.has(i.id) && ['CARD', 'GRANITE', 'DECOM'].includes(i.workflow_type));
+ if (selected.length > 0) return selected.map(i => ({ ip_address: i.ip_address || '', hostname: i.hostname || '' }));
+ // Standalone: use all CARD/GRANITE/DECOM items
+ return items.filter(i => ['CARD', 'GRANITE', 'DECOM'].includes(i.workflow_type)).map(i => ({ ip_address: i.ip_address || '', hostname: i.hostname || '' }));
+ })() : null}
+ />
>
);
}