Fix site filter in Job Details returning no results

Site filter performed client-side against a 1000-row limited deviation set,
causing "No permission deviations found" for any site whose deviations fell
outside that window. Backend now accepts ?site_url= for server-side filtering
without limit; frontend calls the API on filter change instead of filtering
the cached data.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Ivo Oskamp 2026-04-13 17:12:14 +02:00
parent b8446c0665
commit 9c9802205a
2 changed files with 27 additions and 13 deletions

View File

@ -884,8 +884,18 @@
});
});
els.jobSiteFilter.addEventListener('change', function () {
if (state.selectedJobData) {
els.jobSiteFilter.addEventListener('change', async function () {
if (!state.selectedJobId) return;
const siteFilter = els.jobSiteFilter.value;
if (siteFilter) {
// Fetch server-side filtered data (no 1000-row limit)
const filtered = await requestJson(
'/api/scan-jobs/' + encodeURIComponent(state.selectedJobId) +
'?site_url=' + encodeURIComponent(siteFilter)
);
renderJobTables(filtered);
} else {
// "All sites" — use the already-loaded full job data
renderJobTables(state.selectedJobData);
}
});

View File

@ -419,23 +419,27 @@ def export_scan_job(job_id: str, site_url: str | None = None) -> StreamingRespon
@app.get("/api/scan-jobs/{job_id}", response_model=ScanJobDetail)
def get_scan_job(job_id: str) -> ScanJobDetail:
def get_scan_job(job_id: str, site_url: str | None = None) -> ScanJobDetail:
with SessionLocal() as db:
job = db.get(ScanJob, job_id, options=[joinedload(ScanJob.tenant_profile)])
if not job:
raise HTTPException(status_code=404, detail="Job not found")
targets = list(
db.execute(select(ScanTarget).where(ScanTarget.job_id == job.id).order_by(ScanTarget.id.asc())).scalars()
)
deviations = list(
db.execute(
select(PermissionDeviation)
.where(PermissionDeviation.job_id == job.id)
.order_by(PermissionDeviation.id.desc())
.limit(1000)
).scalars()
targets_q = select(ScanTarget).where(ScanTarget.job_id == job.id).order_by(ScanTarget.id.asc())
if site_url:
targets_q = targets_q.where(ScanTarget.site_url == site_url)
targets = list(db.execute(targets_q).scalars())
deviations_q = (
select(PermissionDeviation)
.where(PermissionDeviation.job_id == job.id)
.order_by(PermissionDeviation.site_url.asc(), PermissionDeviation.object_url.asc(), PermissionDeviation.id.asc())
)
if site_url:
deviations_q = deviations_q.where(PermissionDeviation.site_url == site_url)
else:
deviations_q = deviations_q.limit(1000)
deviations = list(db.execute(deviations_q).scalars())
return ScanJobDetail(
**_to_job_summary(job).model_dump(),