Skip to content

Conversation

@raulbob
Copy link
Contributor

@raulbob raulbob commented Dec 5, 2025

Fixed hopefully the pathogen test form

Summary by CodeRabbit

  • New Features

    • Added serology group specification and specification text fields to pathogen test results.
    • Made fatigue symptom globally available (previously restricted to Switzerland).
  • Improvements

    • Enhanced field visibility and visibility controls for regional compliance.
    • Refined country-specific configurations for drug susceptibility testing forms.

✏️ Tip: You can customize this high-level summary in your review settings.

KarnaiahPesula and others added 5 commits December 4, 2025 17:10
Fatigue symptom for all countries
Enabling the test result field.
…usceptibilityForm

- for DrugSusceptibilityForm, added a conditional exit to prevent enabling susceptility contents if country is not Luxembourg
- In PathogenTestForm, moved the call to updateDrugSusceptibilityFields to the end of the listener chain
- Tuberculosis/Latent Tuberculosis is only visible for Luxembourg
- IPI/IMI drug susceptibility is visible for all countries
- also added the DrugSusceptibilityForm changes
@raulbob raulbob linked an issue Dec 5, 2025 that may be closed by this pull request
@coderabbitai
Copy link

coderabbitai bot commented Dec 5, 2025

Walkthrough

This PR adds serogroup specification field mappings to ExternalMessageMapper, removes Switzerland-only restrictions for fatigue in SymptomsDto, refactors PathogenTestForm with new visibility configuration maps for multiple test-related fields, adds UI components for serology data, improves code formatting in PathogenTestController, and introduces country-specific gating logic in DrugSusceptibilityForm for TB-related drug susceptibility visibility.

Changes

Cohort / File(s) Summary
API Field Mappings
sormas-api/src/main/java/de/symeda/sormas/api/externalmessage/processing/ExternalMessageMapper.java
Added two new field mappings in mapToPathogenTest: seroGroupSpecification and seroGroupSpecificationText, following existing Mapping.of pattern.
Symptom DTO Configuration
sormas-api/src/main/java/de/symeda/sormas/api/symptoms/SymptomsDto.java
Removed @HideForCountriesExcept(countries = { CountryHelper.COUNTRY_CODE_SWITZERLAND }) annotation from fatigue field, expanding its global visibility.
PathogenTest UI Layer
sormas-ui/src/main/java/de/symeda/sormas/ui/samples/PathogenTestController.java, sormas-ui/src/main/java/de/symeda/sormas/ui/samples/PathogenTestForm.java
Refactored PathogenTestForm with new visibility configuration maps (RIFAMPICIN_RESISTANT_VISIBILITY_CONDITIONS, TEST_SCALE_VISIBILITY_CONDITIONS, STRAIN_CALL_STATUS_VISIBILITY_CONDITIONS, SPECIE_VISIBILITY_CONDITIONS, PATTERN_PROFILE_VISIBILITY_CONDITIONS, PCR_TEST_SPECIFICATION_VISIBILITY_CONDITIONS); added seroGrpSepcCB (ComboBox) and seroGrpSpecTxt (TextField) UI components with initialization/value-setting logic; generalized result field decision logic into map-based approach; improved code formatting and readability in controller.
Drug Susceptibility Visibility
sormas-ui/src/main/java/de/symeda/sormas/ui/therapy/DrugSusceptibilityForm.java
Enhanced updateFieldsVisibility with early-return guards for null disease and non-antibiotic test types; added country-specific gating to exclude non-Luxembourg TB disease cases; replaced conditional structure with direct applicableFieldIds computation via AnnotationFieldHelper.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

  • PathogenTestForm refactoring: Verify all new visibility maps correctly encode prior conditional logic and that serogroup field initialization/synchronization paths cover all use cases
  • DrugSusceptibilityForm country-specific logic: Confirm Luxembourg TB gating behaves as intended and doesn't unintentionally hide fields
  • ExternalMessageMapper serogroup mappings: Validate that source field extraction and DTO mapping follow the correct pathogen test report structure

Possibly related PRs

  • #13758: Modifies the same SymptomsDto.fatigue country-restriction annotation
  • #13741: Refactors PathogenTestForm disease/test-type visibility logic with null-safety improvements
  • #13680: Adds genotyping-related UI fields to PathogenTestForm alongside this PR's serology fields

Suggested reviewers

  • KarnaiahPesula

Poem

🐰 Sero groups now hop globally free,
Visibility maps spring from every tree,
Fatigue breaks its Swiss alpine cell,
While Luxembourg's TB rules cast their spell,
Field mappings dance, forms refactored with care—
A pathogen test reborn, beyond compare! 🧬✨

Pre-merge checks and finishing touches

❌ Failed checks (2 warnings)
Check name Status Explanation Resolution
Description check ⚠️ Warning The description is vague and incomplete, stating only 'Fixed hopefully the pathogen test form' without referencing issue #13763 or explaining what was fixed. Add the issue number (Fixes #13763) and provide a clear description of the specific problems addressed and changes made to the pathogen test form.
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (1 passed)
Check name Status Explanation
Title check ✅ Passed The title references 'enable the pathogen test result field' and the changes include significant modifications to PathogenTestForm and related components affecting field visibility and behavior.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch bugfix-13763-enable-the-pathogen-test-result-field

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@raulbob raulbob merged commit 67bac4d into development Dec 5, 2025
3 of 11 checks passed
@raulbob raulbob deleted the bugfix-13763-enable-the-pathogen-test-result-field branch December 5, 2025 15:48
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (6)
sormas-ui/src/main/java/de/symeda/sormas/ui/therapy/DrugSusceptibilityForm.java (1)

300-332: Visibility logic is clear; double‑check whether clearing hidden fields for non‑Lux TB/LTBI is intended

The new updateFieldsVisibility control flow looks good overall:

  • Early hiding + early returns keep the method readable and avoid nested ifs.
  • Restricting visibility to ANTIBIOTIC_SUSCEPTIBILITY and driving field selection via AnnotationFieldHelper.getFieldNamesWithMatchingDiseaseAndTestAnnotations is consistent with the annotation‑based pattern elsewhere.
  • Country gating for TB/LTBI using FacadeProvider.getConfigFacade().isConfiguredCountry(CountryHelper.COUNTRY_CODE_LUXEMBOURG) matches the comment intent (only Luxembourg shows TB/LTBI drug susceptibility fields).
  • Heading visibility tied to !applicableFieldIds.isEmpty() is straightforward.

One behavioral nuance to be aware of:

  • At Line 301 you call FieldHelper.hideFieldsNotInList(getFieldGroup(), List.of(), true);, which (with clearOnHidden = true) clears values for all fields that become hidden.
  • For non‑Lux TB/LTBI, the subsequent country check returns early (Lines 318–322), so all drug susceptibility fields remain hidden and cleared.
  • This means that simply visiting/updating the form for TB/LTBI in a non‑Lux country can wipe existing drug‑susceptibility values on save, not just hide the inputs.

If the requirement is purely “do not allow editing / do not show the fields” but keep any already‑stored values, consider avoiding clearing in that code path, for example:

 public void updateFieldsVisibility(Disease disease, PathogenTestType pathogenTestType) {
-    FieldHelper.hideFieldsNotInList(getFieldGroup(), List.of(), true);
+    // Reset visibility without clearing values; we'll clear selectively when needed.
+    FieldHelper.hideFieldsNotInList(getFieldGroup(), List.of(), false);
     formHeadingLabel.setVisible(false);
@@
-    if (!FacadeProvider.getConfigFacade().isConfiguredCountry(CountryHelper.COUNTRY_CODE_LUXEMBOURG)
-        && (disease == Disease.TUBERCULOSIS || disease == Disease.LATENT_TUBERCULOSIS)) {
-        //quit, we do not want to show the fields if TUBERCULOSIS/LATENT_TUBERCULOSIS and we are not in Luxembourg
-        return;
-    }
+    if (!FacadeProvider.getConfigFacade().isConfiguredCountry(CountryHelper.COUNTRY_CODE_LUXEMBOURG)
+        && (disease == Disease.TUBERCULOSIS || disease == Disease.LATENT_TUBERCULOSIS)) {
+        // Quit: keep everything hidden, but retain existing values
+        return;
+    }
@@
-    if (!applicableFieldIds.isEmpty()) {
-        FieldHelper.showOnlyFields(getFieldGroup(), applicableFieldIds, true);
-    }
+    if (!applicableFieldIds.isEmpty()) {
+        // Here it's likely fine to clear hidden fields because we're explicitly scoping which fields apply
+        FieldHelper.showOnlyFields(getFieldGroup(), applicableFieldIds, true);
+    }

If, instead, the business rule is to actively drop these values for non‑Lux TB/LTBI, the current implementation already does that; you may just want to capture it explicitly in the comments or requirements.

sormas-ui/src/main/java/de/symeda/sormas/ui/samples/PathogenTestForm.java (4)

141-221: RESULT_FIELD_DECISION_MAP and visibility condition maps look correct but can be tightened

The new RESULT_FIELD_DECISION_MAP and the various *_VISIBILITY_CONDITIONS maps correctly encode the intended disease/test-type/result combinations and are used consistently later (e.g., in the test type listener and FieldHelper calls).

Two optional improvements for robustness and readability:

  • Consider typing the result map as Map<Disease, List<PathogenTestType>> and using Collections.unmodifiableList(...) for the values, to avoid exposing mutable ArrayList via a public static constant.
  • Likewise, if possible, specialize the visibility maps away from Map<Object, List<Object>> to more specific generic types (or at least document expected key/value types) to help future maintainers.

118-121: Serogroup specification UI wiring is consistent; minor naming and initial-visibility considerations

The new serogroup specification row in the layout and the fields seroGrpSepcCB / seroGrpSpecTxt are correctly:

  • Added to the HTML layout (SERO_GROUP_SPECIFICATION + SERO_GROUP_SPECIFICATION_TEXT).
  • Instantiated in addFields with appropriate types.
  • Synced in setValue with read-only checks.
  • Controlled via FieldHelper.setVisibleWhen for IMI and SeroGroupSpecification.OTHER, as expected.

Two small follow-ups:

  • The variable name seroGrpSepcCB appears to have a typo ("Sepc"). Renaming to seroGrpSpecCB would improve clarity.
  • seroGrpSpecTxt is not explicitly set to invisible before the setVisibleWhen rule (unlike e.g. seroTypingMethodText). If FieldHelper.setVisibleWhen does not reset the initial visibility, you may briefly see the text field before a value is selected. Aligning its initialization with the other conditional fields would avoid any flicker:
-        seroGrpSpecTxt = addField(PathogenTestDto.SERO_GROUP_SPECIFICATION_TEXT, TextField.class);
+        seroGrpSpecTxt = addField(PathogenTestDto.SERO_GROUP_SPECIFICATION_TEXT, TextField.class);
+        seroGrpSpecTxt.setVisible(false);

Also applies to: 242-244, 596-601, 1056-1077


1147-1153: Disease variant listener now drives test result; confirm UX intent

The disease-variant value-change listener now:

  • Forces testResultField to POSITIVE when a non-null DiseaseVariant is selected.
  • Clears testResultField when the variant is cleared.
  • Toggles the details field based on HAS_DETAILS.

This is logically consistent (a specific variant implies a positive test), but it also means clearing the variant will clear any manually entered test result, even if the user set NEGATIVE/NOT_APPLICABLE explicitly.

Please confirm this UX is intended; if not, you may want to only auto-set the result when it was empty before, and avoid clearing a non-empty result when the variant is removed.


1273-1280: Placeholder TestTypeValueChangeListener is empty; remove or document usage

TestTypeValueChangeListener is now an empty inner class with a TODO stub and no logic.

If nothing outside this class relies on its presence, consider removing it entirely to reduce noise. If external code still references it (as the comment suggests), it might be worth adding a brief Javadoc explaining that it’s intentionally a no-op compatibility shim.

sormas-ui/src/main/java/de/symeda/sormas/ui/samples/PathogenTestController.java (1)

383-399: Case result selection and disease-variant update prompting: behavior change is subtle, verify intent

The refactor in handleAssociatedCase and checkForDiseaseVariantUpdate:

  • Picks a single resultedPathogenTest (positive preferred over negative) and only prompts the user once for updating the sample result.
  • Uses !DataHelper.equal(test.getTestedDiseaseVariant(), caze.getDiseaseVariant()) as the sole difference check before calling isNotYetRelatedDiseaseVariant(test) and potentially showing the variant update dialog.

This means you will now also prompt when:

  • The case has a non-null disease variant, and
  • The new test’s testedDiseaseVariant is null, but it’s not already associated (per isNotYetRelatedDiseaseVariant).

The dialog text has been updated to handle [no disease variant], so clearing a case’s variant via a newer test is now possible.

Please confirm this is intentional; if you only want to prompt when a non-null variant is proposed from the test, you likely need to keep an explicit test.getTestedDiseaseVariant() != null guard in the condition.

Also applies to: 550-569

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 6b728b2 and 63005de.

📒 Files selected for processing (5)
  • sormas-api/src/main/java/de/symeda/sormas/api/externalmessage/processing/ExternalMessageMapper.java (1 hunks)
  • sormas-api/src/main/java/de/symeda/sormas/api/symptoms/SymptomsDto.java (0 hunks)
  • sormas-ui/src/main/java/de/symeda/sormas/ui/samples/PathogenTestController.java (8 hunks)
  • sormas-ui/src/main/java/de/symeda/sormas/ui/samples/PathogenTestForm.java (12 hunks)
  • sormas-ui/src/main/java/de/symeda/sormas/ui/therapy/DrugSusceptibilityForm.java (2 hunks)
💤 Files with no reviewable changes (1)
  • sormas-api/src/main/java/de/symeda/sormas/api/symptoms/SymptomsDto.java
🧰 Additional context used
🧬 Code graph analysis (2)
sormas-ui/src/main/java/de/symeda/sormas/ui/therapy/DrugSusceptibilityForm.java (3)
sormas-api/src/main/java/de/symeda/sormas/api/FacadeProvider.java (1)
  • FacadeProvider (128-599)
sormas-api/src/main/java/de/symeda/sormas/api/utils/AnnotationFieldHelper.java (1)
  • AnnotationFieldHelper (26-95)
sormas-ui/src/main/java/de/symeda/sormas/ui/utils/FieldHelper.java (1)
  • FieldHelper (56-1270)
sormas-ui/src/main/java/de/symeda/sormas/ui/samples/PathogenTestController.java (2)
sormas-api/src/main/java/de/symeda/sormas/api/DiseaseHelper.java (1)
  • DiseaseHelper (32-92)
sormas-api/src/main/java/de/symeda/sormas/api/utils/DataHelper.java (1)
  • DataHelper (60-502)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (4)
  • GitHub Check: android app test (27)
  • GitHub Check: SORMAS CI
  • GitHub Check: android app test (28)
  • GitHub Check: android app test (26)
🔇 Additional comments (6)
sormas-ui/src/main/java/de/symeda/sormas/ui/therapy/DrugSusceptibilityForm.java (1)

34-37: New imports are appropriate and scoped to the new gating logic

CountryHelper and FacadeProvider are correctly introduced and only used for the configured‑country check; no unused or redundant imports here.

sormas-ui/src/main/java/de/symeda/sormas/ui/samples/PathogenTestForm.java (3)

313-357: Result auto-selection and drug susceptibility visibility: behavior looks coherent, but confirm edge cases

The extended updateDrugSusceptibilityFieldSpecifications plus the new RESULT_FIELD_DECISION_MAP usage in the test type listener together implement:

  • Environment samples (disease == null) skipping any result auto-changes while still updating drug susceptibility field visibility.
  • Clearing testResultField when testType becomes null.
  • Luxembourg-only defaults for TB and invasive diseases (NOT_APPLICABLE / POSITIVE) via updateDrugSusceptibilityFieldSpecifications.
  • General auto-positives for selected disease/test-type combinations via RESULT_FIELD_DECISION_MAP, with more specific Luxembourg rules taking precedence afterward.

This is a sensible structure and avoids touching environment-sample results.

Two things to double-check:

  • For diseases not in RESULT_FIELD_DECISION_MAP, each test type change now clears testResultField unconditionally. That matches the prior pattern for some flows but will force the user to re-enter a result whenever they change the test type. Confirm this is intended for all diseases not listed in the map.
  • For Luxembourg TB types, RESULT_FIELD_DECISION_MAP does nothing (no TB entries), and the country-specific logic in updateDrugSusceptibilityFieldSpecifications sets the final result — which looks correct and non-conflicting.

Also applies to: 1155-1227


406-418: New genotype and serogroup value synchronization looks safe

The extended setValue now guards all newly synced fields (genoTypingResultTextTF, seroGrpSepcCB, seroGrpSpecTxt) with isReadOnly checks before setting values. This aligns with the existing pattern and should avoid read-only write attempts when loading an existing test.


569-592: Visibility rules for TB- and genotyping-related fields are consistent with new condition maps

The updated visibility wiring:

  • Uses RIFAMPICIN_RESISTANT_VISIBILITY_CONDITIONS, TEST_SCALE_VISIBILITY_CONDITIONS, STRAIN_CALL_STATUS_VISIBILITY_CONDITIONS, and SPECIE_VISIBILITY_CONDITIONS for Luxembourg TB fields.
  • Keeps the MIRU pattern profile using a local dependency map, as before.
  • Adds PCR_TEST_SPECIFICATION_VISIBILITY_CONDITIONS for PCR_TEST_SPECIFICATION across countries.
  • Controls GENOTYPE_RESULT and GENOTYPE_RESULT_TEXT via disease/test/result conditions and the GenoTypeResult.OTHER sentinel.

All of this is consistent with the static maps and should improve maintainability of field visibility. No functional issues spotted.

Also applies to: 983-983, 1080-1109

sormas-ui/src/main/java/de/symeda/sormas/ui/samples/PathogenTestController.java (2)

130-135: Event disease resolution for associated event participant looks good

The refactored block now:

  • Loads the EventParticipantDto by UUID.
  • Uses its EventReferenceDto to fetch the full EventDto and read the disease.

This is clearer than mixing references and full DTOs and ensures you always use the event’s current disease. No issues here.


332-338: Drug susceptibility clearing logic: confirm intended scope for latent TB

The new logic in savePathogenTests:

  • Treats luxTB as “Luxembourg and tested disease is exactly Disease.TUBERCULOSIS”.
  • Uses DiseaseHelper.checkDiseaseIsInvasiveBacterialDiseases for IMI/IPI.
  • Clears p.setDrugSusceptibility(null) when testType == ANTIBIOTIC_SUSCEPTIBILITY but neither luxTB nor invasiveDisease is true.

This ensures antibiotic susceptibility is only persisted for:

  • TB in Luxembourg (not latent TB), and
  • Invasive meningococcal/pneumococcal infections in all countries.

Behavior seems coherent, but please confirm:

  • That susceptibility for Disease.LATENT_TUBERCULOSIS should indeed be dropped even in Luxembourg.
  • That there are no other diseases where ANTIBIOTIC_SUSCEPTIBILITY should be retained.

Comment on lines +345 to +354
Mapping.of(
pathogenTest::setSeroGroupSpecification,
pathogenTest.getSeroGroupSpecification(),
sourceTestReport.getSeroGroupSpecification(),
PathogenTestDto.SERO_GROUP_SPECIFICATION),
Mapping.of(
pathogenTest::setSeroGroupSpecificationText,
pathogenTest.getSeroGroupSpecificationText(),
sourceTestReport.getSeroGroupSpecificationText(),
PathogenTestDto.SERO_GROUP_SPECIFICATION),
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Wrong UI field key for serogroup specification text mapping

The mapping that sets setSeroGroupSpecificationText uses PathogenTestDto.SERO_GROUP_SPECIFICATION as the UI field path instead of the dedicated SERO_GROUP_SPECIFICATION_TEXT constant. This will mark the wrong field as changed and can confuse any UI logic driven by changedFields.

Please switch the field path to the text constant:

-                       Mapping.of(
-                            pathogenTest::setSeroGroupSpecificationText,
-                            pathogenTest.getSeroGroupSpecificationText(),
-                            sourceTestReport.getSeroGroupSpecificationText(),
-                            PathogenTestDto.SERO_GROUP_SPECIFICATION),
+                       Mapping.of(
+                            pathogenTest::setSeroGroupSpecificationText,
+                            pathogenTest.getSeroGroupSpecificationText(),
+                            sourceTestReport.getSeroGroupSpecificationText(),
+                            PathogenTestDto.SERO_GROUP_SPECIFICATION_TEXT),
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
Mapping.of(
pathogenTest::setSeroGroupSpecification,
pathogenTest.getSeroGroupSpecification(),
sourceTestReport.getSeroGroupSpecification(),
PathogenTestDto.SERO_GROUP_SPECIFICATION),
Mapping.of(
pathogenTest::setSeroGroupSpecificationText,
pathogenTest.getSeroGroupSpecificationText(),
sourceTestReport.getSeroGroupSpecificationText(),
PathogenTestDto.SERO_GROUP_SPECIFICATION),
Mapping.of(
pathogenTest::setSeroGroupSpecification,
pathogenTest.getSeroGroupSpecification(),
sourceTestReport.getSeroGroupSpecification(),
PathogenTestDto.SERO_GROUP_SPECIFICATION),
Mapping.of(
pathogenTest::setSeroGroupSpecificationText,
pathogenTest.getSeroGroupSpecificationText(),
sourceTestReport.getSeroGroupSpecificationText(),
PathogenTestDto.SERO_GROUP_SPECIFICATION_TEXT),
🤖 Prompt for AI Agents
In
sormas-api/src/main/java/de/symeda/sormas/api/externalmessage/processing/ExternalMessageMapper.java
around lines 345 to 354, the Mapping that sets setSeroGroupSpecificationText
incorrectly uses PathogenTestDto.SERO_GROUP_SPECIFICATION as the UI field path;
change that mapping to use the dedicated
PathogenTestDto.SERO_GROUP_SPECIFICATION_TEXT constant so the correct UI field
is marked as changed. Ensure only the field path constant is updated for the
setSeroGroupSpecificationText Mapping and leave the rest of the mapping
parameters unchanged.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Enable the Pathogen test result field

3 participants