Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
36 changes: 36 additions & 0 deletions backend/src/jobs/job-monitoring.utils.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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({
Expand All @@ -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({
Expand Down
23 changes: 21 additions & 2 deletions backend/src/jobs/job-monitoring.utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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
}
Expand All @@ -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
}
Expand Down
42 changes: 42 additions & 0 deletions frontend/src/components/JobMonitoringTab.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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) => {
Expand Down Expand Up @@ -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 &amp; Sort
</Button>
Expand Down Expand Up @@ -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 &amp; Sort
</Button>
Expand Down Expand Up @@ -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 &amp; Sort
</Button>
Expand Down
Loading