Library documents from the knowledge base were not checked against
the allowed file extensions before being sent to Ivanti. If a doc
had an unsupported type (e.g. .msg, .eml), Ivanti would reject the
entire workflow with a 400. Now validates library docs the same way
as local uploads and returns a clear error naming the offending file.
Allowed: .pdf, .png, .jpg, .jpeg, .gif, .doc, .docx, .xlsx, .csv, .txt, .zip
When the Ivanti API returns a non-success status, the error message
now includes the actual response body from Ivanti instead of just
the HTTP status code. This makes troubleshooting much easier since
you can see what Ivanti rejected (e.g. invalid field, too many
attachments, malformed request).
The requeue endpoint now handles three scenarios:
1. Original queue items still exist — uses their finding data (ideal case)
2. Queue items deleted (Clear Completed) — looks up findings from
ivanti_findings table using finding_ids_json
3. FP created outside dashboard (no queue_item_ids) — same fallback
to finding_ids_json and ivanti_findings lookup
4. Last resort — creates queue items with just finding IDs if the
findings aren't in ivanti_findings either
New feature: users can re-queue findings from a rejected FP submission
back into the Ivanti todo queue under a different workflow type (FP,
Archer, CARD, GRANITE, or DECOM). Primary use case is when an FP is
rejected with a recommendation to submit an Archer risk acceptance.
Backend:
- New migration: add requeued_at column to ivanti_fp_submissions
- New endpoint: POST /api/ivanti/fp-workflow/submissions/:id/requeue
- Validates workflow_type and vendor (required for FP/Archer/DECOM)
- Creates new pending queue items from original finding data
- Marks submission as requeued (prevents double re-queue)
- Audit logs the action
Frontend (ReportingPage.js):
- RequeueConfirmDialog component with workflow type selector and vendor input
- Re-queue Findings button in Edit FP Modal header (rejected submissions only)
- Already re-queued label when submission.requeued_at is set
- Success notification on completion
When GET /submissions enriches submissions with Ivanti API data, it now
checks if batch.currentState (APPROVED, REJECTED, REWORK) differs from
the local lifecycle_status and updates the DB accordingly. This ensures
approved submissions get filtered out of the queue panel as intended.
Also changed safeText() to return null for non-string Ivanti note values
(arrays/objects) instead of JSON-stringifying them. The notes array
filters nulls via .filter(Boolean) so non-string data is simply hidden.
- All 16 route files now import pool from ../db directly
- Removed db parameter from all factory functions
- All callbacks replaced with async/await pool.query()
- All ? placeholders converted to $1, $2... numbered params
- datetime('now') → NOW(), INSERT OR IGNORE → ON CONFLICT DO NOTHING
- LIKE → ILIKE for case-insensitive searches
- Error detection: err.code === '23505' for unique violations
- server.js no longer passes pool/db/requireAuth to route factories
- Only ivantiFindings.js still receives pool (pending task 8 rewrite)
- Add GET /api/ivanti/fp-workflow/documents/search endpoint for querying the document library
- Update POST /api/ivanti/fp-workflow to accept libraryDocIds for attaching library documents on create
- Update POST .../submissions/:id/attachments to accept libraryDocIds on edit
- Add AttachmentSourcePicker component with local upload and library search modes
- Integrate picker into FpWorkflowModal (create) and FpEditModal (edit)
- Track attachment source (local/library) in attachment_results_json for traceability
- Add resolveWorkflowBatchUuid helper that searches Ivanti API for UUID by batch ID and caches it locally
- Use UUID resolver in findings and attachments endpoints instead of relying on stored UUID
- Store UUID on new FP creation by searching Ivanti after workflow batch is created
- Fix frontend attachment upload field name from 'files' to 'attachments' to match Multer config
- Add migration for lifecycle_status, batch UUID, updated_at columns and submission history table
- Add backend endpoints: GET/PUT/POST/PATCH for viewing, editing, adding findings/attachments, and status changes
- Add pure helpers: validateLifecycleTransition, mergeFindings, buildSubmissionHistoryEntry
- Add FpEditModal with tabbed UI (Details, Findings, Attachments, History)
- Make workflow badges clickable for Reworked/Rejected/Expired states with pencil icon
- Add submissions list section to QueuePanel with lifecycle status badges
- Wire state and data flow in ReportingPage for submissions fetch and edit callbacks
The API expects { subject: 'hostFinding', filterRequest: { filters } }
not a flat filter object. Confirmed working via direct curl test —
workflow ID 33418832 created successfully.
Remove extra fields (orWithPrevious, implicitFilters, subject) that
aren't in the Swagger filter schema. Add projection and sort fields
to match the search endpoint format.
The /workflowBatch/falsePositive/request endpoint expects
multipart/form-data with text fields (name, reason, description,
expirationDate, overrideControl, subjectFilterRequest, isEmptyWorkflow)
and inline file uploads — not a JSON body with separate attachment calls.
- Add ivantiFormPost() helper for mixed form fields + files
- Replace buildIvantiPayload with buildIvantiFormFields + buildSubjectFilterRequest
- Remove separate attachment upload loop (files sent inline)
- Update response handling for { id, created } shape
- Fix copy-paste bug in ivantiFpWorkflow.js where both ternary branches
returned 'partial'; simplified to direct assignment
- Remove unused shouldShowFpButton() from ReportingPage.js (canWrite
from useAuth() is used instead)
- Hoist repeated isCreateFpButtonEnabled() calls into a single variable
in QueuePanel render