Add multi-item Jira ticket creation from Ivanti Queue
Select multiple queue items and create a single consolidated Jira ticket with aggregated summary and description. Adds multi-select mode with checkboxes, floating action bar, consolidation modal, and junction table to track which queue items contributed to each ticket. - Migration: jira_ticket_queue_items junction table - POST /api/jira-tickets/:id/queue-items endpoint - GET /api/ivanti/todo-queue/ticket-links endpoint - ConsolidationModal component with aggregation logic - IvantiTodoQueuePage with selection mode and ticket link badges - Pure utility functions for summary/description generation - 34 tests passing (backend + frontend)
This commit is contained in:
65
backend/migrations/add_multi_item_jira_ticket.js
Normal file
65
backend/migrations/add_multi_item_jira_ticket.js
Normal file
@@ -0,0 +1,65 @@
|
||||
// Migration: Add multi-item Jira ticket junction table
|
||||
// - Creates jira_ticket_queue_items table linking jira_tickets to ivanti_todo_queue items
|
||||
// - Adds UNIQUE constraint on (jira_ticket_id, queue_item_id)
|
||||
// - Adds indexes on queue_item_id and jira_ticket_id
|
||||
// Idempotent — safe to run multiple times.
|
||||
const pool = require('../db');
|
||||
|
||||
async function run() {
|
||||
console.log('Starting multi-item Jira ticket migration...');
|
||||
|
||||
// Verify prerequisite tables exist
|
||||
const { rows: jiraTable } = await pool.query(`
|
||||
SELECT 1 FROM information_schema.tables
|
||||
WHERE table_schema = 'public' AND table_name = 'jira_tickets'
|
||||
`);
|
||||
if (jiraTable.length === 0) {
|
||||
console.error('✗ jira_tickets table does not exist. Cannot proceed.');
|
||||
process.exit(1);
|
||||
}
|
||||
console.log('✓ jira_tickets table exists');
|
||||
|
||||
const { rows: queueTable } = await pool.query(`
|
||||
SELECT 1 FROM information_schema.tables
|
||||
WHERE table_schema = 'public' AND table_name = 'ivanti_todo_queue'
|
||||
`);
|
||||
if (queueTable.length === 0) {
|
||||
console.error('✗ ivanti_todo_queue table does not exist. Cannot proceed.');
|
||||
process.exit(1);
|
||||
}
|
||||
console.log('✓ ivanti_todo_queue table exists');
|
||||
|
||||
// Create junction table
|
||||
await pool.query(`
|
||||
CREATE TABLE IF NOT EXISTS jira_ticket_queue_items (
|
||||
id SERIAL PRIMARY KEY,
|
||||
jira_ticket_id INTEGER NOT NULL REFERENCES jira_tickets(id),
|
||||
queue_item_id INTEGER NOT NULL REFERENCES ivanti_todo_queue(id),
|
||||
created_at TIMESTAMPTZ DEFAULT NOW(),
|
||||
UNIQUE (jira_ticket_id, queue_item_id)
|
||||
)
|
||||
`);
|
||||
console.log('✓ jira_ticket_queue_items table created (or already exists)');
|
||||
|
||||
// Add index on queue_item_id for efficient lookup of tickets by queue item
|
||||
await pool.query(`
|
||||
CREATE INDEX IF NOT EXISTS idx_jira_ticket_queue_items_queue_item
|
||||
ON jira_ticket_queue_items(queue_item_id)
|
||||
`);
|
||||
console.log('✓ queue_item_id index created (or already exists)');
|
||||
|
||||
// Add index on jira_ticket_id for efficient lookup of queue items by ticket
|
||||
await pool.query(`
|
||||
CREATE INDEX IF NOT EXISTS idx_jira_ticket_queue_items_ticket
|
||||
ON jira_ticket_queue_items(jira_ticket_id)
|
||||
`);
|
||||
console.log('✓ jira_ticket_id index created (or already exists)');
|
||||
|
||||
console.log('Migration complete.');
|
||||
process.exit(0);
|
||||
}
|
||||
|
||||
run().catch(err => {
|
||||
console.error('Migration failed:', err.message);
|
||||
process.exit(1);
|
||||
});
|
||||
@@ -23,6 +23,7 @@ const POSTGRES_MIGRATIONS = [
|
||||
'add_compliance_item_history.js',
|
||||
'add_jira_sync_columns_pg.js',
|
||||
'add_flexible_jira_ticket_creation.js',
|
||||
'add_multi_item_jira_ticket.js',
|
||||
];
|
||||
|
||||
async function runAll() {
|
||||
|
||||
Reference in New Issue
Block a user