feat(reporting): add Ivanti queue panel for batch FP/Archer staging

Adds a persistent per-user staging queue so analysts can tag findings
during review and batch-process Ivanti workflows in one focused session.

Backend:
- New ivanti_todo_queue table (user-scoped, vendor, workflow_type, status)
- Table auto-created on server startup via idempotent CREATE IF NOT EXISTS
- New route /api/ivanti/todo-queue: GET, POST, PUT/:id, DELETE/:id,
  DELETE/completed — all scoped to req.user.id

Frontend (ReportingPage):
- Fixed checkbox column on findings table; clicking opens an add-to-queue
  popover (portal) with vendor input and FP/Archer toggle
- Already-queued rows show checked/disabled checkbox
- Queue slide-out panel (420px fixed, CSS transition) with items grouped
  by vendor, per-item complete toggle + delete, Clear Completed footer
- Queue button in header with live pending-count badge

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-03-26 14:10:53 -06:00
parent 1520cc994b
commit 887d11610e
4 changed files with 828 additions and 5 deletions

View File

@@ -22,6 +22,7 @@ const createKnowledgeBaseRouter = require('./routes/knowledgeBase');
const createArcherTicketsRouter = require('./routes/archerTickets');
const createIvantiWorkflowsRouter = require('./routes/ivantiWorkflows');
const createIvantiFindingsRouter = require('./routes/ivantiFindings');
const createIvantiTodoQueueRouter = require('./routes/ivantiTodoQueue');
const app = express();
const PORT = process.env.PORT || 3001;
@@ -123,8 +124,34 @@ app.use('/uploads', express.static('uploads', {
// Database connection
const db = new sqlite3.Database('./cve_database.db', (err) => {
if (err) console.error('Database connection error:', err);
else console.log('Connected to CVE database');
if (err) {
console.error('Database connection error:', err);
return;
}
console.log('Connected to CVE database');
// Ensure ivanti_todo_queue table exists (idempotent migration)
db.run(`
CREATE TABLE IF NOT EXISTS ivanti_todo_queue (
id INTEGER PRIMARY KEY AUTOINCREMENT,
user_id INTEGER NOT NULL,
finding_id TEXT NOT NULL,
finding_title TEXT,
cves_json TEXT,
vendor TEXT NOT NULL,
workflow_type TEXT NOT NULL CHECK(workflow_type IN ('FP', 'Archer')),
status TEXT NOT NULL DEFAULT 'pending' CHECK(status IN ('pending', 'complete')),
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
updated_at DATETIME DEFAULT CURRENT_TIMESTAMP,
FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE
)
`, (err2) => {
if (err2) console.error('Failed to create ivanti_todo_queue table:', err2);
else db.run(
'CREATE INDEX IF NOT EXISTS idx_todo_queue_user ON ivanti_todo_queue(user_id, status)',
(err3) => { if (err3) console.error('Failed to create todo_queue index:', err3); }
);
});
});
// Auth routes (public)
@@ -187,6 +214,9 @@ app.use('/api/ivanti/workflows', createIvantiWorkflowsRouter(db, requireAuth));
// Ivanti / RiskSense host findings routes (all authenticated users)
app.use('/api/ivanti/findings', createIvantiFindingsRouter(db, requireAuth));
// Ivanti queue routes — per-user staging queue for FP / Archer workflows
app.use('/api/ivanti/todo-queue', createIvantiTodoQueueRouter(db, requireAuth));
// ========== CVE ENDPOINTS ==========
// Get all CVEs with optional filters (authenticated users)