fix(reporting): smart-flip queue popover + add CARD workflow type
Popover now flips above the row when it would overflow the bottom of the viewport, and clamps horizontally to stay within the window. Adds CARD as a third workflow type (for out-of-team asset disposition in CARD) alongside FP and Archer. CARD is styled in green (#10B981) across the popover toggle and queue panel badge. DB: new migration (add_card_workflow_type.js) recreates ivanti_todo_queue with an updated CHECK constraint to allow 'CARD'; run manually on dev. App-level validation in the route is updated to match. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
78
backend/migrations/add_card_workflow_type.js
Normal file
78
backend/migrations/add_card_workflow_type.js
Normal file
@@ -0,0 +1,78 @@
|
||||
// Migration: Add CARD to workflow_type CHECK constraint on ivanti_todo_queue
|
||||
// SQLite cannot ALTER a CHECK constraint, so this recreates the table.
|
||||
const sqlite3 = require('sqlite3').verbose();
|
||||
const path = require('path');
|
||||
|
||||
const dbPath = path.join(__dirname, '..', 'cve_database.db');
|
||||
const db = new sqlite3.Database(dbPath);
|
||||
|
||||
console.log('Starting add_card_workflow_type migration...');
|
||||
|
||||
db.serialize(() => {
|
||||
db.run('PRAGMA foreign_keys = OFF', (err) => {
|
||||
if (err) console.error('PRAGMA error:', err);
|
||||
});
|
||||
|
||||
db.run('BEGIN TRANSACTION', (err) => {
|
||||
if (err) { console.error('BEGIN error:', err); return; }
|
||||
});
|
||||
|
||||
db.run(`
|
||||
CREATE TABLE ivanti_todo_queue_new (
|
||||
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', 'CARD')),
|
||||
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
|
||||
)
|
||||
`, (err) => {
|
||||
if (err) console.error('Error creating new table:', err);
|
||||
else console.log('✓ ivanti_todo_queue_new created');
|
||||
});
|
||||
|
||||
db.run(
|
||||
'INSERT INTO ivanti_todo_queue_new SELECT * FROM ivanti_todo_queue',
|
||||
(err) => {
|
||||
if (err) console.error('Error copying data:', err);
|
||||
else console.log('✓ Data copied');
|
||||
}
|
||||
);
|
||||
|
||||
db.run('DROP TABLE ivanti_todo_queue', (err) => {
|
||||
if (err) console.error('Error dropping old table:', err);
|
||||
else console.log('✓ Old table dropped');
|
||||
});
|
||||
|
||||
db.run(
|
||||
'ALTER TABLE ivanti_todo_queue_new RENAME TO ivanti_todo_queue',
|
||||
(err) => {
|
||||
if (err) console.error('Error renaming table:', err);
|
||||
else console.log('✓ Table renamed');
|
||||
}
|
||||
);
|
||||
|
||||
db.run(
|
||||
'CREATE INDEX IF NOT EXISTS idx_todo_queue_user ON ivanti_todo_queue(user_id, status)',
|
||||
(err) => {
|
||||
if (err) console.error('Error creating index:', err);
|
||||
else console.log('✓ Index recreated');
|
||||
}
|
||||
);
|
||||
|
||||
db.run('COMMIT', (err) => {
|
||||
if (err) console.error('COMMIT error:', err);
|
||||
else console.log('✓ Transaction committed');
|
||||
});
|
||||
|
||||
db.run('PRAGMA foreign_keys = ON', () => {});
|
||||
});
|
||||
|
||||
db.close(() => {
|
||||
console.log('Migration complete!');
|
||||
});
|
||||
@@ -1,7 +1,7 @@
|
||||
// routes/ivantiTodoQueue.js
|
||||
const express = require('express');
|
||||
|
||||
const VALID_WORKFLOW_TYPES = ['FP', 'Archer'];
|
||||
const VALID_WORKFLOW_TYPES = ['FP', 'Archer', 'CARD'];
|
||||
const VALID_STATUSES = ['pending', 'complete'];
|
||||
|
||||
function isValidVendor(vendor) {
|
||||
|
||||
@@ -139,7 +139,7 @@ const db = new sqlite3.Database('./cve_database.db', (err) => {
|
||||
finding_title TEXT,
|
||||
cves_json TEXT,
|
||||
vendor TEXT NOT NULL,
|
||||
workflow_type TEXT NOT NULL CHECK(workflow_type IN ('FP', 'Archer')),
|
||||
workflow_type TEXT NOT NULL CHECK(workflow_type IN ('FP', 'Archer', 'CARD')),
|
||||
status TEXT NOT NULL DEFAULT 'pending' CHECK(status IN ('pending', 'complete')),
|
||||
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
|
||||
updated_at DATETIME DEFAULT CURRENT_TIMESTAMP,
|
||||
|
||||
Reference in New Issue
Block a user