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
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ public class EpiDataDto extends PseudonymizableDto {
public static final String CASE_IMPORTED_STATUS = "caseImportedStatus";
public static final String CLUSTER_TYPE = "clusterType";
public static final String CLUSTER_TYPE_TEXT = "clusterTypeText";
public static final String CLUSTER_RELATED = "clusterRelated";

private YesNoUnknown exposureDetailsKnown;
private YesNoUnknown activityAsCaseDetailsKnown;
Expand All @@ -71,6 +72,11 @@ public class EpiDataDto extends PseudonymizableDto {
@HideForCountriesExcept(countries = {CountryHelper.COUNTRY_CODE_LUXEMBOURG})
private ClusterType clusterType;

@Diseases({
Disease.MEASLES})
@HideForCountriesExcept(countries = {CountryHelper.COUNTRY_CODE_LUXEMBOURG})
private boolean clusterRelated;

@HideForCountriesExcept(countries = {CountryHelper.COUNTRY_CODE_LUXEMBOURG})
@Diseases({
Disease.MEASLES})
Expand Down Expand Up @@ -189,6 +195,14 @@ public void setClusterTypeText(String clusterTypeText) {
this.clusterTypeText = clusterTypeText;
}

public boolean isClusterRelated() {
return clusterRelated;
}

public void setClusterRelated(boolean clusterRelated) {
this.clusterRelated = clusterRelated;
}

@Override
public EpiDataDto clone() throws CloneNotSupportedException {
EpiDataDto clone = (EpiDataDto) super.clone();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1561,6 +1561,7 @@ public interface Captions {
String EpiData_activityAsCaseDetailsKnown = "EpiData.activityAsCaseDetailsKnown";
String EpiData_areaInfectedAnimals = "EpiData.areaInfectedAnimals";
String EpiData_caseImportedStatus = "EpiData.caseImportedStatus";
String EpiData_clusterRelated = "EpiData.clusterRelated";
String EpiData_clusterType = "EpiData.clusterType";
String EpiData_clusterTypeText = "EpiData.clusterTypeText";
String EpiData_contactWithSourceCaseKnown = "EpiData.contactWithSourceCaseKnown";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -134,7 +134,8 @@ public enum PathogenTestType {
CQ_VALUE_DETECTION,

@Diseases(value = {
Disease.RESPIRATORY_SYNCYTIAL_VIRUS })
Disease.RESPIRATORY_SYNCYTIAL_VIRUS,
Disease.MEASLES})
SEQUENCING,

@Diseases(value = {
Expand Down
1 change: 1 addition & 0 deletions sormas-api/src/main/resources/captions.properties
Original file line number Diff line number Diff line change
Expand Up @@ -1145,6 +1145,7 @@ EpiData.highTransmissionRiskArea=Residing or working in an area with high risk o
EpiData.largeOutbreaksArea=Residing or travelling to countries/territories/areas experiencing larger outbreaks of local transmission
EpiData.contactWithSourceCaseKnown=Contacts with source case known
EpiData.caseImportedStatus=Case imported status
EpiData.clusterRelated=Cluster Related
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Verification agent

🧩 Analysis chain

Match caption casing with neighboring keys

Use sentence case to be consistent with adjacent EpiData captions (e.g., “Case imported status”, “Cluster type”) and with existing “contactRelated=Contact related”.

-EpiData.clusterRelated=Cluster Related
+EpiData.clusterRelated=Cluster related

Run to ensure the new key exists across all locale bundles:


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "All caption bundles:"
fd -a 'captions.*\.properties' -t f | sort

echo -e "\nBundles missing EpiData.clusterRelated:"
while read -r f; do
  if ! rg -n '^EpiData\.clusterRelated=' "$f" >/dev/null; then
    echo " - $f"
  fi
done < <(fd -a 'captions.*\.properties' -t f)

Length of output: 4084


🏁 Script executed:

#!/bin/bash
set -euo pipefail

caption_files=( $(fd -a 'captions.*\.properties' -t f) )

echo "Caption bundles found: ${#caption_files[@]}"
if [ ${#caption_files[@]} -eq 0 ]; then
  echo "No caption bundles found."
  exit 0
fi

missing=()
found=()
for f in "${caption_files[@]}"; do
  match=$(rg -n '^EpiData\.clusterRelated=' "$f" 2>/dev/null || true)
  if [ -n "$match" ]; then
    echo "FOUND: $match"
    found+=("$f")
  else
    echo "MISSING: $f"
    missing+=("$f")
  fi
done

echo
printf 'Summary: %d found, %d missing\n' "${#found[@]}" "${#missing[@]}"

if [ ${#missing[@]} -gt 0 ]; then
  printf '\nBundles missing EpiData.clusterRelated:\n'
  for mf in "${missing[@]}"; do printf ' - %s\n' "$mf"; done
  exit 1
else
  echo "All bundles contain EpiData.clusterRelated"
fi

Length of output: 8563


Match caption casing with neighboring keys — change value and propagate key

Change in sormas-api/src/main/resources/captions.properties (line 1148):

-EpiData.clusterRelated=Cluster Related
+EpiData.clusterRelated=Cluster related

Add EpiData.clusterRelated= to these bundles (currently missing; 52 files):

  • sormas-api/src/main/resources/captions_ar-SA.properties
  • sormas-api/src/main/resources/captions_ar.properties
  • sormas-api/src/main/resources/captions_cs-CZ.properties
  • sormas-api/src/main/resources/captions_de-CH.properties
  • sormas-api/src/main/resources/captions_de-DE.properties
  • sormas-api/src/main/resources/captions_en-AF.properties
  • sormas-api/src/main/resources/captions_en-GH.properties
  • sormas-api/src/main/resources/captions_en-GM.properties
  • sormas-api/src/main/resources/captions_en-KE.properties
  • sormas-api/src/main/resources/captions_en-LR.properties
  • sormas-api/src/main/resources/captions_en-NG.properties
  • sormas-api/src/main/resources/captions_en.properties
  • sormas-api/src/main/resources/captions_es-BO.properties
  • sormas-api/src/main/resources/captions_es-CU.properties
  • sormas-api/src/main/resources/captions_es-EC.properties
  • sormas-api/src/main/resources/captions_es-ES.properties
  • sormas-api/src/main/resources/captions_fa-AF.properties
  • sormas-api/src/main/resources/captions_fi-FI.properties
  • sormas-api/src/main/resources/captions_fil-PH.properties
  • sormas-api/src/main/resources/captions_fj-FJ.properties
  • sormas-api/src/main/resources/captions_fr-CD.properties
  • sormas-api/src/main/resources/captions_fr-CH.properties
  • sormas-api/src/main/resources/captions_fr-FR.properties
  • sormas-api/src/main/resources/captions_fr-TN.properties
  • sormas-api/src/main/resources/captions_haw-US.properties
  • sormas-api/src/main/resources/captions_hi-IN.properties
  • sormas-api/src/main/resources/captions_hr-HR.properties
  • sormas-api/src/main/resources/captions_it-CH.properties
  • sormas-api/src/main/resources/captions_it-IT.properties
  • sormas-api/src/main/resources/captions_ja-JP.properties
  • sormas-api/src/main/resources/captions_ks-PK.properties
  • sormas-api/src/main/resources/captions_ku-TR.properties
  • sormas-api/src/main/resources/captions_la-LA.properties
  • sormas-api/src/main/resources/captions_lv-LV.properties
  • sormas-api/src/main/resources/captions_mt-MT.properties
  • sormas-api/src/main/resources/captions_ne-NP.properties
  • sormas-api/src/main/resources/captions_nl-NL.properties
  • sormas-api/src/main/resources/captions_no-NO.properties
  • sormas-api/src/main/resources/captions_pl-PL.properties
  • sormas-api/src/main/resources/captions_ps-AF.properties
  • sormas-api/src/main/resources/captions_pt-BR.properties
  • sormas-api/src/main/resources/captions_pt-CV.properties
  • sormas-api/src/main/resources/captions_pt-PT.properties
  • sormas-api/src/main/resources/captions_ro-RO.properties
  • sormas-api/src/main/resources/captions_ru-RU.properties
  • sormas-api/src/main/resources/captions_sv-SE.properties
  • sormas-api/src/main/resources/captions_sw-KE.properties
  • sormas-api/src/main/resources/captions_tr-TR.properties
  • sormas-api/src/main/resources/captions_uk-UA.properties
  • sormas-api/src/main/resources/captions_ur-PK.properties
  • sormas-api/src/main/resources/captions_zh-CN.properties
  • sormas-api/src/main/resources/captions_zu-ZA.properties
📝 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
EpiData.clusterRelated=Cluster Related
EpiData.clusterRelated=Cluster related
🤖 Prompt for AI Agents
In sormas-api/src/main/resources/captions.properties around line 1148, the key
EpiData.clusterRelated has value "Cluster Related" whose casing should match
neighboring keys; update the value to the correct casing (e.g., "Cluster
related") and add the same key with an appropriate translated value to each of
the listed locale bundles (the 52 captions_*.properties files) so they contain
EpiData.clusterRelated=<translated value>; ensure existing file encoding/format
preserved and keys are added in logical alphabetical group or near related
EpiData keys.

EpiData.clusterType=Cluster type
EpiData.clusterTypeText=Specify cluster type text
#Therapy
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
import java.util.List;

import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.EnumType;
import javax.persistence.Enumerated;
Expand Down Expand Up @@ -56,6 +57,7 @@ public class EpiData extends AbstractDomainObject {
private CaseImportedStatus caseImportedStatus;
private ClusterType clusterType;
private String clusterTypeText;
private boolean clusterRelated;

private List<Exposure> exposures = new ArrayList<>();
Comment thread
KarnaiahPesula marked this conversation as resolved.
private List<ActivityAsCase> activitiesAsCase = new ArrayList<>();
Expand Down Expand Up @@ -170,4 +172,13 @@ public String getClusterTypeText() {
public void setClusterTypeText(String clusterTypeText) {
this.clusterTypeText = clusterTypeText;
}

@Column(nullable = false)
public boolean isClusterRelated() {
return clusterRelated;
}

public void setClusterRelated(boolean clusterRelated) {
this.clusterRelated = clusterRelated;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,7 @@ public EpiData fillOrBuildEntity(EpiDataDto source, EpiData target, boolean chec
target.setClusterType(source.getClusterType());
target.setCaseImportedStatus(source.getCaseImportedStatus());
target.setClusterTypeText(source.getClusterTypeText());
target.setClusterRelated(source.isClusterRelated());

return target;
}
Expand Down Expand Up @@ -249,6 +250,7 @@ public static EpiDataDto toDto(EpiData epiData) {
target.setClusterType(source.getClusterType());
target.setCaseImportedStatus(source.getCaseImportedStatus());
target.setClusterTypeText(source.getClusterTypeText());
target.setClusterRelated(source.isClusterRelated());

return target;
}
Expand Down
8 changes: 8 additions & 0 deletions sormas-backend/src/main/resources/sql/sormas_schema.sql
Original file line number Diff line number Diff line change
Expand Up @@ -14647,5 +14647,13 @@ ALTER TABLE testreport_history ADD COLUMN IF NOT EXISTS tubemitogenegt10 boolean

INSERT INTO schema_version (version_number, comment) VALUES (591, 'Implement functionality to receive messages from laboratory for TB #13563');

-- 2025-09-09 - Lux measles - cluster related checkbox #13365
alter table epidata add column IF NOT EXISTS clusterRelated boolean DEFAULT false;
update epidata set clusterRelated = false where clusterRelated is null;
alter table epidata alter column clusterRelated set not null;
alter table epidata_history add column IF NOT EXISTS clusterRelated boolean DEFAULT false;
update epidata_history set clusterRelated = false where clusterRelated is null;
alter table epidata_history alter column clusterRelated set not null;
INSERT INTO schema_version (version_number, comment) VALUES (592, 'Added cluster related checkbox for LUX Measles #13365');

-- *** Insert new sql commands BEFORE this line. Remember to always consider _history tables. ***
Original file line number Diff line number Diff line change
Expand Up @@ -1079,7 +1079,7 @@ public void testAutomaticClassificationForIMI() {
caze.setEpidemiologicalConfirmation(YesNoUnknown.YES);
caze = getCaseFacade().save(caze);
caze = getCaseFacade().getCaseDataByUuid(caze.getUuid());
assertEquals(CaseClassification.PROBABLE, caze.getCaseClassification());
assertEquals(CaseClassification.SUSPECT, caze.getCaseClassification());

// Confirmed
caze = getCaseFacade().save(buildSuspectCase(Disease.INVASIVE_MENINGOCOCCAL_INFECTION));
Expand Down Expand Up @@ -1137,7 +1137,7 @@ public void ruleOutFalsePositivesForIMI() {
PathogenTestType.PCR_RT_PCR,
PathogenTestType.ANTIGEN_DETECTION, PathogenTestType.ANTIBIOTIC_SUSCEPTIBILITY);
caze = getCaseFacade().getCaseDataByUuid(caze.getUuid());
assertEquals(CaseClassification.PROBABLE, caze.getCaseClassification());
assertEquals(CaseClassification.SUSPECT, caze.getCaseClassification());
}

@Test
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -179,6 +179,7 @@ public class ContactDataForm extends AbstractEditForm<ContactDto> {
private final ViewMode viewMode;
private final Disease disease;
private final boolean diseaseHasFollowUp;
private final boolean luxMeasles;
private NullableOptionGroup contactProximity;
Comment thread
KarnaiahPesula marked this conversation as resolved.
private ComboBox region;
private ComboBox district;
Expand Down Expand Up @@ -219,6 +220,7 @@ public ContactDataForm(Disease disease, ViewMode viewMode, boolean isPseudonymiz
this.viewMode = viewMode;
this.disease = disease;
this.diseaseHasFollowUp = FacadeProvider.getDiseaseConfigurationFacade().hasFollowUp(disease);
this.luxMeasles = Disease.MEASLES == disease && FacadeProvider.getConfigFacade().isConfiguredCountry(CountryHelper.COUNTRY_CODE_LUXEMBOURG);
addFields();
}

Expand All @@ -241,7 +243,7 @@ protected void addFields() {
Label followUpStausHeadingLabel = new Label(I18nProperties.getString(Strings.headingFollowUpStatus));
followUpStausHeadingLabel.addStyleName(H3);
getContent().addComponent(followUpStausHeadingLabel, FOLLOW_UP_STATUS_HEADING_LOC);
followUpStausHeadingLabel.setVisible(diseaseHasFollowUp);
followUpStausHeadingLabel.setVisible(diseaseHasFollowUp && !isLuxMeasles(this.disease));

Label prophylaxisLabel = new Label(I18nProperties.getString(Strings.headingProphylaxisLoc));
prophylaxisLabel.addStyleName(H3);
Expand Down Expand Up @@ -889,6 +891,20 @@ private void updateDiseaseConfiguration(Disease disease) {
field -> diseaseHasFollowUp,
field -> false);

// For LUX measles cases do not require the follow-up details. For other countries works as it is
FieldHelper.setMultipleVisible(
getFieldGroup(),
Arrays.asList(
ContactDto.FOLLOW_UP_STATUS,
ContactDto.FOLLOW_UP_STATUS_CHANGE_DATE,
ContactDto.FOLLOW_UP_STATUS_CHANGE_USER,
ContactDto.FOLLOW_UP_COMMENT,
ContactDto.FOLLOW_UP_UNTIL,
ContactDto.CONTACT_OFFICER,
ContactDto.OVERWRITE_FOLLOW_UP_UNTIL),
field -> !isLuxMeasles(disease),
field -> false);

FieldHelper.updateEnumData(
contactProximity,
Arrays.asList(ContactProximity.getValues(disease, FacadeProvider.getConfigFacade().getCountryLocale())));
Expand Down Expand Up @@ -1140,4 +1156,14 @@ public void setValue(ContactDto newFieldValue) throws ReadOnlyException, Convert
// this hopefully resets everything to its correct value
discard();
}

/**
* To validate the Lux specific measles rules
*
* @param disease
* @return
*/
private boolean isLuxMeasles(Disease disease) {
return Disease.MEASLES == disease && isConfiguredServer(CountryHelper.COUNTRY_CODE_LUXEMBOURG);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@
import java.util.function.Supplier;

import com.vaadin.v7.ui.TextField;
import de.symeda.sormas.api.CountryHelper;
import de.symeda.sormas.api.epidata.ClusterType;
import de.symeda.sormas.api.utils.fieldaccess.UiFieldAccessCheckers;
import de.symeda.sormas.api.utils.fieldvisibility.checkers.CountryFieldVisibilityChecker;
Expand Down Expand Up @@ -81,7 +82,7 @@ public class EpiDataForm extends AbstractEditForm<EpiDataDto> {
loc(EpiDataDto.ACTIVITY_AS_CASE_DETAILS_KNOWN)+
loc(EpiDataDto.ACTIVITIES_AS_CASE) +
loc(LOC_CLUSTER_TYPE_HEADING)+
fluidRowLocs(6,EpiDataDto.CLUSTER_TYPE,6,EpiDataDto.CLUSTER_TYPE_TEXT) +
fluidRowLocs(3, EpiDataDto.CLUSTER_RELATED,5,EpiDataDto.CLUSTER_TYPE,4,EpiDataDto.CLUSTER_TYPE_TEXT) +
locCss(VSPACE_TOP_3, LOC_EPI_DATA_FIELDS_HINT) +
loc(EpiDataDto.HIGH_TRANSMISSION_RISK_AREA) +
loc(EpiDataDto.LARGE_OUTBREAKS_AREA) +
Expand Down Expand Up @@ -152,7 +153,9 @@ protected void addFields() {

addField(EpiDataDto.CASE_IMPORTED_STATUS);
addField(EpiDataDto.CLUSTER_TYPE);
addField(EpiDataDto.CLUSTER_RELATED);
TextField clustorTypeTF = addField(EpiDataDto.CLUSTER_TYPE_TEXT);
FieldHelper.setVisibleWhen(getFieldGroup(), EpiDataDto.CLUSTER_TYPE, EpiDataDto.CLUSTER_RELATED, Collections.singletonList(Boolean.TRUE), true);
FieldHelper.setVisibleWhen(getField(EpiDataDto.CLUSTER_TYPE), Arrays.asList(clustorTypeTF), Arrays.asList(ClusterType.OTHER), true);
Comment thread
KarnaiahPesula marked this conversation as resolved.
FieldHelper.setVisibleWhen(
getFieldGroup(),
Expand Down Expand Up @@ -210,11 +213,12 @@ private void addHeadingsAndInfoTexts() {
new MultilineLabel(divsCss(VSPACE_3, I18nProperties.getString(Strings.infoEpiDataFieldsHint)), ContentMode.HTML),
LOC_EPI_DATA_FIELDS_HINT);

getContent().addComponent(new MultilineLabel(h3(I18nProperties.getString(Strings.headingEpiCaseImport)) + divsCss(VSPACE_3), ContentMode.HTML),
LOC_CASE_IMPORT_HEADING);

getContent().addComponent(new MultilineLabel(h3(I18nProperties.getString(Strings.headingClusterType)) + divsCss(VSPACE_3), ContentMode.HTML),
LOC_CLUSTER_TYPE_HEADING);
if (isConfiguredServer(CountryHelper.COUNTRY_CODE_LUXEMBOURG) && Disease.MEASLES == disease) {
getContent().addComponent(new MultilineLabel(h3(I18nProperties.getString(Strings.headingEpiCaseImport)) + divsCss(VSPACE_3), ContentMode.HTML),
LOC_CASE_IMPORT_HEADING);
getContent().addComponent(new MultilineLabel(h3(I18nProperties.getString(Strings.headingClusterType)) + divsCss(VSPACE_3), ContentMode.HTML),
LOC_CLUSTER_TYPE_HEADING);
}

getContent().addComponent(
new MultilineLabel(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -363,11 +363,7 @@ protected void addFields() {

// Initialize means of immunization field based on current disease
if (currentDisease != null) {
FieldHelper.updateItems(
meansOfImmunizationField,
Arrays.asList(MeansOfImmunization.values()),
FieldVisibilityCheckers.withDisease(currentDisease),
MeansOfImmunization.class);
updateMeansOfImmunizationField(currentDisease);
}

if (disease != null) {
Expand Down
Loading