From b8e09bc3b5cd14974e900275275e6cd9a98d05c2 Mon Sep 17 00:00:00 2001 From: plakkara Date: Tue, 28 Jul 2026 14:15:16 -0400 Subject: [PATCH 1/3] inserted filenames in the summary columns of job list and history tables --- backend/src/jobs/job-monitoring.utils.spec.ts | 48 ++++++++++++++++--- backend/src/jobs/job-monitoring.utils.ts | 23 ++++++++- 2 files changed, 63 insertions(+), 8 deletions(-) diff --git a/backend/src/jobs/job-monitoring.utils.spec.ts b/backend/src/jobs/job-monitoring.utils.spec.ts index c3b24b0c..bf1f9b72 100644 --- a/backend/src/jobs/job-monitoring.utils.spec.ts +++ b/backend/src/jobs/job-monitoring.utils.spec.ts @@ -2,12 +2,12 @@ import { JobStatus } from './enums/job-status.enum' import { JobTrigger } from './enums/job-trigger.enum' import { JobType } from './enums/job-type.enum' import { - formatJobDisplayName, - formatJobSummary, - formatMonitoringStatus, - formatTriggeredBy, - MONITORED_JOB_HISTORY_TYPES, - MONITORED_JOB_LIST_TYPES, + formatJobDisplayName, + formatJobSummary, + formatMonitoringStatus, + formatTriggeredBy, + MONITORED_JOB_HISTORY_TYPES, + MONITORED_JOB_LIST_TYPES, } from './job-monitoring.utils' describe('job-monitoring.utils', () => { @@ -111,6 +111,27 @@ describe('job-monitoring.utils', () => { ).toBe('2 files processed, 10 accepted, 1 rejected') }) + it('includes CRA response file names in weekly response summary', () => { + expect( + formatJobSummary({ + jobType: JobType.POLL_CRA_RESPONSE, + status: JobStatus.SUCCESS, + metadata: { + files_processed: 3, + file_names: [ + 'craUserId.ARSP0001.txt', + 'craUserId.AWKL0001.txt', + 'craUserId.ARSP0002.txt', + ], + records_accepted: 10, + records_rejected: 1, + }, + }), + ).toBe( + '3 files processed (craUserId.ARSP0001.txt, craUserId.AWKL0001.txt +1 more), 10 accepted, 1 rejected', + ) + }) + it('formats send CRA no-batch summary from metadata', () => { expect( formatJobSummary({ @@ -121,6 +142,21 @@ describe('job-monitoring.utils', () => { ).toBe('No batch to process') }) + it('includes CRA outbound file name in send CRA summary', () => { + expect( + formatJobSummary({ + jobType: JobType.SEND_CRA_FILE, + status: JobStatus.SUCCESS, + metadata: { + batch_id: 8155, + file_name: 'II20260728.0001.dat', + record_count: 24, + contacts_count: 24, + }, + }), + ).toBe('Batch 8155, file II20260728.0001.dat, 24 records, 24 contacts') + }) + it('formats ingest data summary from child job metadata', () => { expect( formatJobSummary({ diff --git a/backend/src/jobs/job-monitoring.utils.ts b/backend/src/jobs/job-monitoring.utils.ts index 2de3b5e2..ba823ace 100644 --- a/backend/src/jobs/job-monitoring.utils.ts +++ b/backend/src/jobs/job-monitoring.utils.ts @@ -86,6 +86,18 @@ export function formatJobSummary( return null } + const formatFileNames = (value: unknown): string | null => { + if (!Array.isArray(value)) return null + + const names = value + .map((name) => (typeof name === 'string' ? name.trim() : '')) + .filter((name) => name.length > 0) + + if (names.length === 0) return null + if (names.length <= 2) return names.join(', ') + return `${names.slice(0, 2).join(', ')} +${names.length - 2} more` + } + switch (job.jobType) { case JobType.INGEST_ICM: { const fetched = metadata.totalFetched ?? metadata.fetched @@ -126,10 +138,15 @@ export function formatJobSummary( return 'No batch to process' } const batchId = metadata.batch_id + const fileName = typeof metadata.file_name === 'string' ? metadata.file_name : undefined const recordCount = metadata.record_count const contactsCount = metadata.contacts_count if (batchId !== undefined) { - return `Batch ${batchId}, ${recordCount ?? 0} records, ${contactsCount ?? 0} contacts` + const filePart = fileName ? `file ${fileName}, ` : '' + return `Batch ${batchId}, ${filePart}${recordCount ?? 0} records, ${contactsCount ?? 0} contacts` + } + if (fileName) { + return `File ${fileName} sent` } break } @@ -141,7 +158,9 @@ export function formatJobSummary( } const accepted = metadata.records_accepted ?? 0 const rejected = metadata.records_rejected ?? 0 - return `${filesProcessed} files processed, ${accepted} accepted, ${rejected} rejected` + const fileNames = formatFileNames(metadata.file_names) + const filePart = fileNames ? ` (${fileNames})` : '' + return `${filesProcessed} files processed${filePart}, ${accepted} accepted, ${rejected} rejected` } break } From 5798d4e1e8e0f8b3abbfa0c0b0a34d8739d7d994 Mon Sep 17 00:00:00 2001 From: plakkara Date: Tue, 28 Jul 2026 15:55:10 -0400 Subject: [PATCH 2/3] fixed failing tests --- backend/src/jobs/job-monitoring.utils.spec.ts | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/backend/src/jobs/job-monitoring.utils.spec.ts b/backend/src/jobs/job-monitoring.utils.spec.ts index bf1f9b72..d66e4313 100644 --- a/backend/src/jobs/job-monitoring.utils.spec.ts +++ b/backend/src/jobs/job-monitoring.utils.spec.ts @@ -2,12 +2,12 @@ import { JobStatus } from './enums/job-status.enum' import { JobTrigger } from './enums/job-trigger.enum' import { JobType } from './enums/job-type.enum' import { - formatJobDisplayName, - formatJobSummary, - formatMonitoringStatus, - formatTriggeredBy, - MONITORED_JOB_HISTORY_TYPES, - MONITORED_JOB_LIST_TYPES, + formatJobDisplayName, + formatJobSummary, + formatMonitoringStatus, + formatTriggeredBy, + MONITORED_JOB_HISTORY_TYPES, + MONITORED_JOB_LIST_TYPES, } from './job-monitoring.utils' describe('job-monitoring.utils', () => { From c0ef67f5d99cd76db019db789183bd7d74ba7add Mon Sep 17 00:00:00 2001 From: plakkara Date: Tue, 28 Jul 2026 16:28:46 -0400 Subject: [PATCH 3/3] disabled clear button --- frontend/src/components/JobMonitoringTab.tsx | 42 ++++++++++++++++++++ 1 file changed, 42 insertions(+) diff --git a/frontend/src/components/JobMonitoringTab.tsx b/frontend/src/components/JobMonitoringTab.tsx index 5ce53e2b..206655f5 100644 --- a/frontend/src/components/JobMonitoringTab.tsx +++ b/frontend/src/components/JobMonitoringTab.tsx @@ -595,6 +595,30 @@ export default function JobMonitoringTab() { setSelectedJobHistoryId(null) } + const isJobListClearActive = + jlFilterId !== '' || + jlFilterName !== '' || + jlFilterStatus !== '' || + jlFilterTrigger !== '' || + jlSortField !== 'id' || + jlSortOrder !== 'asc' + + const isJobHistoryClearActive = + jhAppliedFilterId !== '' || + jhFilterJobName !== '' || + jhFilterStatus !== '' || + jhFilterTrigger !== '' || + jhSortField !== 'startedAt' || + jhSortOrder !== 'desc' + + const isActivitiesClearActive = + actFilterSeverity !== '' || + actFilterType !== '' || + actAppliedFilterJobId !== '' || + selectedJobHistoryId !== null || + actSortField !== 'when' || + actSortOrder !== 'desc' + // ── Job List: client-side filter + sort ────────────────────────────────── const filteredJobList = jobListData .filter((row) => { @@ -635,6 +659,12 @@ export default function JobMonitoringTab() { onClick={clearJobListFilters} variant="outlined" color="inherit" + disabled={!isJobListClearActive} + sx={{ + opacity: isJobListClearActive ? 1 : 0.45, + filter: isJobListClearActive ? 'none' : 'blur(0.6px)', + transition: 'opacity 0.2s ease, filter 0.2s ease', + }} > Clear Filters & Sort @@ -856,6 +886,12 @@ export default function JobMonitoringTab() { onClick={clearJobHistoryFilters} variant="outlined" color="inherit" + disabled={!isJobHistoryClearActive} + sx={{ + opacity: isJobHistoryClearActive ? 1 : 0.45, + filter: isJobHistoryClearActive ? 'none' : 'blur(0.6px)', + transition: 'opacity 0.2s ease, filter 0.2s ease', + }} > Clear Filters & Sort @@ -1154,6 +1190,12 @@ export default function JobMonitoringTab() { onClick={clearActivitiesFilters} variant="outlined" color="inherit" + disabled={!isActivitiesClearActive} + sx={{ + opacity: isActivitiesClearActive ? 1 : 0.45, + filter: isActivitiesClearActive ? 'none' : 'blur(0.6px)', + transition: 'opacity 0.2s ease, filter 0.2s ease', + }} > Clear Filters & Sort