3.8 KiB
3.8 KiB
Tasks
Task 1: Database Migration — Add dismissed_at Column
- 1.1 Create migration file
backend/migrations/add_fp_submissions_dismissed.jsthat adds adismissed_at TIMESTAMPTZ DEFAULT NULLcolumn to theivanti_fp_submissionstable usingALTER TABLE ... ADD COLUMN IF NOT EXISTS - 1.2 Run the migration and verify the column exists in the database schema
Task 2: Backend — Dismiss Endpoint
- 2.1 Add
PATCH /submissions/:id/dismissendpoint tobackend/routes/ivantiFpWorkflow.jswithrequireAuth()andrequireGroup('Admin', 'Standard_User')middleware - 2.2 Implement ownership verification (user_id match, return 403 if mismatch)
- 2.3 Implement lifecycle guard (only
lifecycle_status === 'rejected'can be dismissed, return 400 otherwise) - 2.4 Set
dismissed_at = NOW()on the submission record on success - 2.5 Log audit entry with action
ivanti_fp_submission_dismissed, entity_typeivanti_workflow, and the workflow batch ID as entity_id
Task 3: Backend — Pure Filter Function
- 3.1 Create and export
filterVisibleSubmissions(submissions)function inbackend/routes/ivantiFpWorkflow.jsthat excludes submissions withlifecycle_status === 'approved'ordismissed_at !== null - 3.2 Create and export
shouldShowDismissButton(submission)predicate that returns true only whenlifecycle_status === 'rejected'anddismissed_atis null
Task 4: Frontend — Filter Approved and Dismissed Submissions
- 4.1 Modify the
fpSubmissionsuseMemo inReportingPage.jsto filter out submissions wherelifecycle_status === 'approved'ordismissed_atis not null before passing to the QueuePanel - 4.2 Verify that the FpEditModal can still be opened for approved submissions from Reporting Table workflow badges (no filtering on that path)
Task 5: Frontend — Dismiss Button on Rejected Submissions
- 5.1 Add an X button (lucide
Xicon, 12px) to the right side of submission rows wherelifecycle_status === 'rejected'in the QueuePanel submissions section - 5.2 Implement click handler that calls
PATCH /api/ivanti/fp-workflow/submissions/:id/dismissand removes the submission from the visible list on success - 5.3 Use
e.stopPropagation()on the X button to prevent triggering the row's click-to-edit handler - 5.4 Show error feedback if the dismiss API call fails
Task 6: Frontend — Collapsible Submissions Section
- 6.1 Add
submissionsCollapsedstate initialized fromlocalStorage.getItem('steam_submissions_collapsed'), defaulting tofalse(expanded) - 6.2 Add a clickable chevron icon (ChevronDown when expanded, ChevronUp when collapsed) to the SUBMISSIONS header row
- 6.3 Conditionally render the submissions list based on collapsed state — when collapsed, hide the list but keep the header with the count badge visible
- 6.4 Persist collapsed/expanded state to localStorage on toggle using key
steam_submissions_collapsed
Task 7: Property-Based Tests
- 7.1 Create
backend/__tests__/fp-submissions-cleanup.property.test.jswith fast-check - 7.2 Implement Property 1 test: for any array of submissions with random lifecycle_status and dismissed_at values,
filterVisibleSubmissionsreturns only non-approved and non-dismissed submissions (min 100 iterations) - 7.3 Implement Property 2 test: for any submission with random lifecycle_status and dismissed_at,
shouldShowDismissButtonreturns true iff status is 'rejected' and dismissed_at is null (min 100 iterations)
Task 8: Unit and Integration Tests
- 8.1 Write unit tests for the dismiss endpoint (happy path, wrong status, ownership check, not found)
- 8.2 Write unit tests for filter edge cases (all approved, all dismissed, mixed, empty array)
- 8.3 Write integration test verifying dismissed submissions remain in the database but are excluded from the filtered list