Add FP submissions cleanup: auto-clear approved, dismiss rejected, collapsible section

This commit is contained in:
Jordan Ramos
2026-05-11 14:29:50 -06:00
parent cda1eaadc9
commit 7245352496
6 changed files with 495 additions and 11 deletions

View File

@@ -88,6 +88,14 @@ function buildSubmissionHistoryEntry(changeType, details, userId, username) {
return { user_id: userId, username: username, change_type: changeType, change_details_json: JSON.stringify(details), created_at: new Date().toISOString() };
}
function filterVisibleSubmissions(submissions) {
return submissions.filter(s => s.lifecycle_status !== 'approved' && s.dismissed_at == null);
}
function shouldShowDismissButton(submission) {
return submission.lifecycle_status === 'rejected' && submission.dismissed_at == null;
}
// ---------------------------------------------------------------------------
// Resolve workflow batch UUID
// ---------------------------------------------------------------------------
@@ -723,6 +731,45 @@ function createIvantiFpWorkflowRouter() {
});
});
// PATCH /submissions/:id/dismiss — Dismiss a rejected submission
router.patch('/submissions/:id/dismiss', requireAuth(), requireGroup('Admin', 'Standard_User'), (req, res) => {
(async () => {
const submissionId = req.params.id;
const { rows: subRows } = await pool.query(
`SELECT * FROM ivanti_fp_submissions WHERE id = $1`, [submissionId]
);
const submission = subRows[0];
if (!submission) return res.status(404).json({ error: 'Submission not found.' });
if (submission.user_id !== req.user.id) return res.status(403).json({ error: 'You can only dismiss your own submissions.' });
if (submission.lifecycle_status !== 'rejected') return res.status(400).json({ error: 'Only rejected submissions can be dismissed.' });
try {
await pool.query(
`UPDATE ivanti_fp_submissions SET dismissed_at = NOW() WHERE id = $1`,
[submissionId]
);
} catch (dbErr) {
console.error('Failed to set dismissed_at:', dbErr);
return res.status(500).json({ error: 'Internal server error.' });
}
logAudit({
userId: req.user.id, username: req.user.username,
action: 'ivanti_fp_submission_dismissed', entityType: 'ivanti_workflow',
entityId: String(submission.ivanti_workflow_batch_id),
details: { submissionId },
ipAddress: req.ip
});
res.json({ success: true });
})().catch((unexpectedErr) => {
console.error('Unexpected error in PATCH /submissions/:id/dismiss:', unexpectedErr);
res.status(500).json({ error: 'Internal server error.' });
});
});
// PATCH /submissions/:id/status — Update lifecycle status
router.patch('/submissions/:id/status', requireAuth(), requireGroup('Admin', 'Standard_User'), (req, res) => {
(async () => {
@@ -787,3 +834,5 @@ module.exports.isAllowedFileExtension = isAllowedFileExtension;
module.exports.validateLifecycleTransition = validateLifecycleTransition;
module.exports.mergeFindings = mergeFindings;
module.exports.buildSubmissionHistoryEntry = buildSubmissionHistoryEntry;
module.exports.filterVisibleSubmissions = filterVisibleSubmissions;
module.exports.shouldShowDismissButton = shouldShowDismissButton;