fix: Faceted Counts — NULL-Werte einbeziehen + AbortController fuer Race Conditions
All checks were successful
CI/CD / go-lint (push) Has been skipped
CI/CD / python-lint (push) Has been skipped
CI/CD / nodejs-lint (push) Has been skipped
CI/CD / test-go-ai-compliance (push) Successful in 34s
CI/CD / test-python-backend-compliance (push) Successful in 32s
CI/CD / test-python-document-crawler (push) Successful in 21s
CI/CD / test-python-dsms-gateway (push) Successful in 17s
CI/CD / validate-canonical-controls (push) Successful in 11s
CI/CD / Deploy (push) Successful in 2s

Backend: Facets zaehlen jetzt Controls OHNE Wert (z.B. "Ohne Nachweis")
als __none__. Filter unterstuetzen __none__ fuer verification_method,
category, evidence_type. Counts addieren sich immer zum Total.

Frontend: "Ohne X" Optionen in Dropdowns. AbortController verhindert
dass aeltere API-Antworten neuere ueberschreiben.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Benjamin Admin
2026-03-26 17:35:52 +01:00
parent 52e463a7c8
commit ac42a0aaa0
2 changed files with 87 additions and 42 deletions

View File

@@ -347,14 +347,23 @@ async def list_controls(
query += " AND release_state = :rs"
params["rs"] = release_state
if verification_method:
query += " AND verification_method = :vm"
params["vm"] = verification_method
if verification_method == "__none__":
query += " AND verification_method IS NULL"
else:
query += " AND verification_method = :vm"
params["vm"] = verification_method
if category:
query += " AND category = :cat"
params["cat"] = category
if category == "__none__":
query += " AND category IS NULL"
else:
query += " AND category = :cat"
params["cat"] = category
if evidence_type:
query += " AND evidence_type = :et"
params["et"] = evidence_type
if evidence_type == "__none__":
query += " AND evidence_type IS NULL"
else:
query += " AND evidence_type = :et"
params["et"] = evidence_type
if target_audience:
query += " AND target_audience LIKE :ta_pattern"
params["ta_pattern"] = f'%"{target_audience}"%'
@@ -434,14 +443,23 @@ async def count_controls(
query += " AND release_state = :rs"
params["rs"] = release_state
if verification_method:
query += " AND verification_method = :vm"
params["vm"] = verification_method
if verification_method == "__none__":
query += " AND verification_method IS NULL"
else:
query += " AND verification_method = :vm"
params["vm"] = verification_method
if category:
query += " AND category = :cat"
params["cat"] = category
if category == "__none__":
query += " AND category IS NULL"
else:
query += " AND category = :cat"
params["cat"] = category
if evidence_type:
query += " AND evidence_type = :et"
params["et"] = evidence_type
if evidence_type == "__none__":
query += " AND evidence_type IS NULL"
else:
query += " AND evidence_type = :et"
params["et"] = evidence_type
if target_audience:
query += " AND target_audience LIKE :ta_pattern"
params["ta_pattern"] = f'%"{target_audience}"%'
@@ -506,14 +524,23 @@ async def controls_meta(
clauses.append("release_state = :rs")
p["rs"] = release_state
if verification_method and skip != "verification_method":
clauses.append("verification_method = :vm")
p["vm"] = verification_method
if verification_method == "__none__":
clauses.append("verification_method IS NULL")
else:
clauses.append("verification_method = :vm")
p["vm"] = verification_method
if category and skip != "category":
clauses.append("category = :cat")
p["cat"] = category
if category == "__none__":
clauses.append("category IS NULL")
else:
clauses.append("category = :cat")
p["cat"] = category
if evidence_type and skip != "evidence_type":
clauses.append("evidence_type = :et")
p["et"] = evidence_type
if evidence_type == "__none__":
clauses.append("evidence_type IS NULL")
else:
clauses.append("evidence_type = :et")
p["et"] = evidence_type
if target_audience and skip != "target_audience":
clauses.append("target_audience LIKE :ta_pattern")
p["ta_pattern"] = f'%"{target_audience}"%'
@@ -598,28 +625,28 @@ async def controls_meta(
GROUP BY severity ORDER BY severity
"""), p_sev).fetchall()
# Verification method facet
# Verification method facet (include NULLs as __none__)
w_vm, p_vm = _build_where(skip="verification_method")
vm_counts = db.execute(text(f"""
SELECT verification_method, count(*) as cnt
FROM canonical_controls WHERE {w_vm} AND verification_method IS NOT NULL
GROUP BY verification_method ORDER BY verification_method
SELECT COALESCE(verification_method, '__none__') as vm, count(*) as cnt
FROM canonical_controls WHERE {w_vm}
GROUP BY vm ORDER BY vm
"""), p_vm).fetchall()
# Category facet
# Category facet (include NULLs as __none__)
w_cat, p_cat = _build_where(skip="category")
cat_counts = db.execute(text(f"""
SELECT category, count(*) as cnt
FROM canonical_controls WHERE {w_cat} AND category IS NOT NULL
GROUP BY category ORDER BY cnt DESC
SELECT COALESCE(category, '__none__') as cat, count(*) as cnt
FROM canonical_controls WHERE {w_cat}
GROUP BY cat ORDER BY cnt DESC
"""), p_cat).fetchall()
# Evidence type facet
# Evidence type facet (include NULLs as __none__)
w_et, p_et = _build_where(skip="evidence_type")
et_counts = db.execute(text(f"""
SELECT evidence_type, count(*) as cnt
FROM canonical_controls WHERE {w_et} AND evidence_type IS NOT NULL
GROUP BY evidence_type ORDER BY evidence_type
SELECT COALESCE(evidence_type, '__none__') as et, count(*) as cnt
FROM canonical_controls WHERE {w_et}
GROUP BY et ORDER BY et
"""), p_et).fetchall()
# Release state facet