Skip to content

Commit e331bcd

Browse files
raulbobobinna-h-nKarnaiahPesularoldySORMAS-Robot
authored
Task 13886 customizable fields metadata values handling (#13908)
* #13828 - Add customizable field metadata and values infrastructure Implements the customizable fields (metadata and values): API Layer: - Added CustomizableFieldType enum with 11 supported field types - Added CustomizableFieldMetadataDto and CustomizableFieldCustomProperties for field configuration - Added CustomizableFieldValueDto with typed value accessors for all supported types - Added CustomizableFieldVisibilityRestrictions and CustomizableFieldVisibilityContext for disease-based field visibility control - Added CustomizableFieldMetadataFacade and CustomizableFieldValueFacade interfaces Backend Layer: - Added CustomizableFieldMetadata and CustomizableFieldValue JPA entities with JSON support - Added CustomizableFieldMetadataService and CustomizableFieldValueService with query methods - Added EJB facades for metadata and value management with full serialization support - Added database schema migration with proper indexing, history tables, and triggers - Added initial testing with CustomizableFieldFacadeEjbTest REST API: - Added CustomizableFieldMetadataResource for metadata CRUD and field operations - Added CustomizableFieldValueResource for value management UI Layer: - Extend AbstractEditForm to support preloaded metadata and values - Added CustomizableFieldsGroup component for grouping fields by UI group - Added CustomizableFieldInput base class with Binder integration for automatic value sync - Implement 11 concrete input components for all supported field types: TEXT, TEXTAREA, NUMBER, DECIMAL, DATE, DATE_TIME, COMBOBOX, CHECKBOX, YES_NO_UNKNOWN, CHECKBOX_LIST, RADIO_BUTTON_LIST - Added CustomizableFieldInputFactory for polymorphic component creation - Support field visibility restrictions, mandatory/readonly flags, and UI weighting * add enums, modify entities, dtos required for exposure form redesign * Updated action versions * Added manual trigger * Added manual trigger * Fixed sormas app barcodescanner version * Removed manual trigger, corrected gradle validate version * Disabled linter, fixed maven ci * Disabled codeql * Disabled codeql * Fixing codeql * Re-added build step * Enabled maven tests * Temporarily disabled open canary * Merge pull request #13893 from SORMAS-Foundation/task-update_github_actions Updated app ci token * Summary: Malaria and Dengue Sample and Pathogentestform changes. Changes: #13801 #13814 * Fixed the possible issues * Review fixes for exposure dates * Review fixes for exposure dates * fix for possible script failure * #13711 - Update Android app to support multiple contact proximities. Migrate contactProximity from single enum to Set<ContactProximity> in the Android app to match the API/backend changes. * Resolve PR comments in-line with the initial commit * Resolve PR comments in-line with the initial commit * Avoid silent drift between the transient set and persisted JSON & Add null check in both updateContactCategory() and getContactCategoryForProximity() to handle malformed proximity data * Fix missing import * Prevents NPE when Gson deserializes unknown enum values as null entries in the Set<ContactProximity> * Changed OpenAPI Canary to fail on incompatible * Changed image to ubuntu-latest for app ci action * Resolved test failures * corrected the latest case * Updated Jacoco tool version to 0.8.14 to avoid bytecode failures * Corrected coderabit suggestion * [GitHub Actions] Update openAPI spec files * Dengue review comments * Updated app ci action Updated YAML syntax for GitHub Actions workflow, including enabling KVM, fixing quotes, and adjusting cache keys. * [GitHub Actions] Update openAPI spec files * Update sql schema with TestReport renamed columns (#13901) * Update sql schema with TestReport renamed columns * Fixed remarks in sql schema * Updated java ci to avoid unnecessary commits for swagger files Add check to avoid committing if no changes are detected. * #13883 - Fixed IGRA inputs value change listeners - Refactored duplicated listeners for IGRA inputs into two listeners - Fixed error caused by locale conversions with IGRA numeric inputs * Added guards against number conversion errors * Removed full type reference * implement ui for new exposure form exposures changes * implement ui for disease specific configuration of exposure user interface * remove schema name from alter table statements * #13828 - Add customizable field metadata and values infrastructure Implements the customizable fields (metadata and values): API Layer: - Added CustomizableFieldType enum with 11 supported field types - Added CustomizableFieldMetadataDto and CustomizableFieldCustomProperties for field configuration - Added CustomizableFieldValueDto with typed value accessors for all supported types - Added CustomizableFieldVisibilityRestrictions and CustomizableFieldVisibilityContext for disease-based field visibility control - Added CustomizableFieldMetadataFacade and CustomizableFieldValueFacade interfaces Backend Layer: - Added CustomizableFieldMetadata and CustomizableFieldValue JPA entities with JSON support - Added CustomizableFieldMetadataService and CustomizableFieldValueService with query methods - Added EJB facades for metadata and value management with full serialization support - Added database schema migration with proper indexing, history tables, and triggers - Added initial testing with CustomizableFieldFacadeEjbTest REST API: - Added CustomizableFieldMetadataResource for metadata CRUD and field operations - Added CustomizableFieldValueResource for value management UI Layer: - Extend AbstractEditForm to support preloaded metadata and values - Added CustomizableFieldsGroup component for grouping fields by UI group - Added CustomizableFieldInput base class with Binder integration for automatic value sync - Implement 11 concrete input components for all supported field types: TEXT, TEXTAREA, NUMBER, DECIMAL, DATE, DATE_TIME, COMBOBOX, CHECKBOX, YES_NO_UNKNOWN, CHECKBOX_LIST, RADIO_BUTTON_LIST - Added CustomizableFieldInputFactory for polymorphic component creation - Support field visibility restrictions, mandatory/readonly flags, and UI weighting * Fixed sormas_schema * Improved UI Group handling and fixed other issues - UI Group is now an enum instead of a string tied to Context - Added handling for translation of captions and descriptions - Improved rendering of YesNoUnkown component * Added better handling for customizable field deletionconfiguration - fixed history triggers - added customizable fields tables to export * Modified field value metadata uuid to strong typed * Tweeked enum handling, added CustomizableFieldValue table partitions * Hide customizable field group on UI when no fields * Added customizable field admin UI and Case Form integration * Fixed EJB local inject causing test failures * Removed customizable field value table partitioning, not supported by unit tests postgres v10 * Fixed history tables --------- Co-authored-by: Obinna Henry <55580796+obinna-h-n@users.noreply.github.com> Co-authored-by: Karnaiah Pesula <karnaiah.pesula@sormas.org> Co-authored-by: Harold <harryasiimwe@gmail.com> Co-authored-by: sormas-robot <accounts@sormas.org>
1 parent ac0e072 commit e331bcd

85 files changed

Lines changed: 7402 additions & 399 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

sormas-api/src/main/java/de/symeda/sormas/api/FacadeProvider.java

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,8 @@
3939
import de.symeda.sormas.api.clinicalcourse.ClinicalVisitFacade;
4040
import de.symeda.sormas.api.contact.ContactFacade;
4141
import de.symeda.sormas.api.customizableenum.CustomizableEnumFacade;
42+
import de.symeda.sormas.api.customizablefield.CustomizableFieldMetadataFacade;
43+
import de.symeda.sormas.api.customizablefield.CustomizableFieldValueFacade;
4244
import de.symeda.sormas.api.dashboard.DashboardFacade;
4345
import de.symeda.sormas.api.dashboard.adverseeventsfollowingimmunization.AefiDashboardFacade;
4446
import de.symeda.sormas.api.dashboard.sample.SampleDashboardFacade;
@@ -508,6 +510,14 @@ public static CustomizableEnumFacade getCustomizableEnumFacade() {
508510
return get().lookupEjbRemote(CustomizableEnumFacade.class);
509511
}
510512

513+
public static CustomizableFieldMetadataFacade getCustomizableFieldMetadataFacade() {
514+
return get().lookupEjbRemote(CustomizableFieldMetadataFacade.class);
515+
}
516+
517+
public static CustomizableFieldValueFacade getCustomizableFieldValueFacade() {
518+
return get().lookupEjbRemote(CustomizableFieldValueFacade.class);
519+
}
520+
511521
public static InfoFacade getInfoFacade() {
512522
return get().lookupEjbRemote(InfoFacade.class);
513523
}

sormas-api/src/main/java/de/symeda/sormas/api/common/DeletableEntityType.java

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,5 +30,7 @@ public enum DeletableEntityType {
3030
PATHOGEN_TEST,
3131
ENVIRONMENT,
3232
ENVIRONMENT_SAMPLE,
33-
SELF_REPORT;
33+
SELF_REPORT,
34+
CUSTOMIZABLE_FIELD_METADATA,
35+
CUSTOMIZABLE_FIELD_VALUE;
3436
}
Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
/*
2+
* SORMAS® - Surveillance Outbreak Response Management & Analysis System
3+
* Copyright © 2016-2026 SORMAS Foundation gGmbH
4+
* This program is free software: you can redistribute it and/or modify
5+
* it under the terms of the GNU General Public License as published by
6+
* the Free Software Foundation, either version 3 of the License, or
7+
* (at your option) any later version.
8+
* This program is distributed in the hope that it will be useful,
9+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
10+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11+
* GNU General Public License for more details.
12+
* You should have received a copy of the GNU General Public License
13+
* along with this program. If not, see <https://www.gnu.org/licenses/>.
14+
*/
15+
16+
package de.symeda.sormas.api.customizablefield;
17+
18+
import de.symeda.sormas.api.EntityDto;
19+
import de.symeda.sormas.api.caze.CaseDataDto;
20+
import de.symeda.sormas.api.epidata.EpiDataDto;
21+
import de.symeda.sormas.api.exposure.ExposureDto;
22+
23+
/**
24+
* Defines supported customizable field contexts and links them to existing
25+
* SORMAS DTO classes. Contexts must reference real DTOs; defining a custom
26+
* field for a non-existent DTO does not make sense.
27+
*/
28+
public enum CustomizableFieldContext {
29+
30+
CASE(CaseDataDto.class),
31+
EPIDATA(EpiDataDto.class),
32+
EXPOSURE(ExposureDto.class);
33+
34+
// add other contexts here
35+
36+
private final String contextClassName;
37+
38+
CustomizableFieldContext(Class<? extends EntityDto> dtoClass) {
39+
this.contextClassName = dtoClass.getName();
40+
}
41+
42+
public String getContextClassName() {
43+
return contextClassName;
44+
}
45+
46+
public static CustomizableFieldContext fromDtoClass(Class<? extends EntityDto> dtoClass) {
47+
return fromDtoClassName(dtoClass.getName());
48+
}
49+
50+
public static CustomizableFieldContext fromDtoClassName(String dtoClassName) {
51+
Class<?> rawClass;
52+
try {
53+
rawClass = Class.forName(dtoClassName);
54+
} catch (ClassNotFoundException e) {
55+
throw new IllegalArgumentException("Unknown context DTO: " + dtoClassName, e);
56+
}
57+
if (!EntityDto.class.isAssignableFrom(rawClass)) {
58+
throw new IllegalArgumentException("Context class is not an EntityDto: " + dtoClassName);
59+
}
60+
for (CustomizableFieldContext context : values()) {
61+
if (context.contextClassName.equals(dtoClassName)) {
62+
return context;
63+
}
64+
}
65+
throw new IllegalArgumentException("Unknown context DTO: " + dtoClassName);
66+
}
67+
}
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
/*
2+
* SORMAS® - Surveillance Outbreak Response Management & Analysis System
3+
* Copyright © 2016-2026 SORMAS Foundation gGmbH
4+
* This program is free software: you can redistribute it and/or modify
5+
* it under the terms of the GNU General Public License as published by
6+
* the Free Software Foundation, either version 3 of the License, or
7+
* (at your option) any later version.
8+
* This program is distributed in the hope that it will be useful,
9+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
10+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11+
* GNU General Public License for more details.
12+
* You should have received a copy of the GNU General Public License
13+
* along with this program. If not, see <https://www.gnu.org/licenses/>.
14+
*/
15+
16+
package de.symeda.sormas.api.customizablefield;
17+
18+
import java.io.Serializable;
19+
import java.util.List;
20+
21+
/**
22+
* Typed representation of the {@code customProperties} JSON column on
23+
* {@link CustomizableFieldMetadataDto}.
24+
* <p>
25+
* Field-type-specific configuration lives here:
26+
* <ul>
27+
* <li><b>options</b> – selectable string values used by
28+
* {@link CustomizableFieldType#COMBOBOX},
29+
* {@link CustomizableFieldType#CHECKBOX_LIST}, and
30+
* {@link CustomizableFieldType#RADIO_BUTTON_LIST}.</li>
31+
* </ul>
32+
* Additional properties can be added here as the feature grows without
33+
* touching the database schema (the whole object is stored as a single
34+
* {@code jsonb} column).
35+
*/
36+
public class CustomizableFieldCustomProperties implements Serializable {
37+
38+
private static final long serialVersionUID = 1L;
39+
40+
/**
41+
* The list of selectable option values for list-type fields
42+
* ({@code COMBOBOX}, {@code CHECKBOX_LIST}, {@code RADIO_BUTTON_LIST}).
43+
* Each entry is the raw stored string value (not a display label).
44+
*/
45+
private List<String> options;
46+
47+
public CustomizableFieldCustomProperties() {
48+
// Required for JSON deserialization.
49+
}
50+
51+
public List<String> getOptions() {
52+
return options;
53+
}
54+
55+
public void setOptions(List<String> options) {
56+
this.options = options;
57+
}
58+
}
Lines changed: 117 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,117 @@
1+
/*
2+
* SORMAS® - Surveillance Outbreak Response Management & Analysis System
3+
* Copyright © 2016-2026 SORMAS Foundation gGmbH
4+
* This program is free software: you can redistribute it and/or modify
5+
* it under the terms of the GNU General Public License as published by
6+
* the Free Software Foundation, either version 3 of the License, or
7+
* (at your option) any later version.
8+
* This program is distributed in the hope that it will be useful,
9+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
10+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11+
* GNU General Public License for more details.
12+
* You should have received a copy of the GNU General Public License
13+
* along with this program. If not, see <https://www.gnu.org/licenses/>.
14+
*/
15+
16+
package de.symeda.sormas.api.customizablefield;
17+
18+
import java.util.ArrayList;
19+
import java.util.List;
20+
21+
/**
22+
* Defines UI groups for customizable fields, scoped to a specific {@link CustomizableFieldContext}.
23+
* <p>
24+
* Each group has a stable string {@link #key} that is used as:
25+
* <ul>
26+
* <li>the value stored in the database;</li>
27+
* <li>the Vaadin layout location ID when embedding a {@code CustomizableFieldsGroup} component.</li>
28+
* </ul>
29+
* <p>
30+
* To add a new group, append an enum value with the owning context and a unique, stable key.
31+
* The key must not be changed after data has been stored against it.
32+
*/
33+
public enum CustomizableFieldGroup {
34+
35+
// ---- CASE groups --------------------------------------------------------
36+
CASE_DATA_GENERAL(CustomizableFieldContext.CASE, "caseDataGeneral"),
37+
CASE_DATA_CLASSIFICATION(CustomizableFieldContext.CASE, "caseDataClassification"),
38+
CASE_DATA_INVESTIGATION(CustomizableFieldContext.CASE, "caseDataInvestigation"),
39+
CASE_DATA_IDENTIFIERS(CustomizableFieldContext.CASE, "caseDataIdentifiers"),
40+
CASE_DATA_DISEASE(CustomizableFieldContext.CASE, "caseDataDisease"),
41+
CASE_DATA_REINFECTION(CustomizableFieldContext.CASE, "caseDataReinfection"),
42+
CASE_DATA_OUTCOME(CustomizableFieldContext.CASE, "caseDataOutcome"),
43+
CASE_DATA_SEQUELAE(CustomizableFieldContext.CASE, "caseDataSequelae"),
44+
CASE_DATA_JURISDICTION(CustomizableFieldContext.CASE, "caseDataJurisdiction"),
45+
CASE_DATA_PLACE_OF_STAY(CustomizableFieldContext.CASE, "caseDataPlaceOfStay"),
46+
CASE_DATA_QUARANTINE(CustomizableFieldContext.CASE, "caseDataQuarantine"),
47+
CASE_DATA_REPORT_GEO(CustomizableFieldContext.CASE, "caseDataReportGeo"),
48+
CASE_DATA_HEALTH_CONDITIONS(CustomizableFieldContext.CASE, "caseDataHealthConditions"),
49+
CASE_DATA_DIAGNOSTIC(CustomizableFieldContext.CASE, "caseDataDiagnostic"),
50+
CASE_DATA_MEDICAL_INFORMATION(CustomizableFieldContext.CASE, "caseDataMedicalInformation"),
51+
CASE_DATA_VACCINATION(CustomizableFieldContext.CASE, "caseDataVaccination"),
52+
CASE_DATA_CLINICIAN_NOTIFICATION(CustomizableFieldContext.CASE, "caseDataClinicianNotification"),
53+
CASE_DATA_CONTACT_TRACING(CustomizableFieldContext.CASE, "caseDataContactTracing"),
54+
55+
// ---- EPIDATA groups -----------------------------------------------------
56+
EPIDATA_EXPOSURE_INVESTIGATION(CustomizableFieldContext.EPIDATA, "exposureInvestigation"),
57+
EPIDATA_ACTIVITY_AS_CASE(CustomizableFieldContext.EPIDATA, "activityAsCase"),
58+
EPIDATA_CONTACT_WITH_SOURCE_CASE(CustomizableFieldContext.EPIDATA, "contactWithSourceCase"),
59+
60+
// ---- EXPOSURE groups ----------------------------------------------------
61+
EXPOSURE_DETAILS(CustomizableFieldContext.EXPOSURE, "exposureDetails"),
62+
EXPOSURES_GENERAL(CustomizableFieldContext.EXPOSURE, "exposuresGeneral"),
63+
LOCATION_GENERAL(CustomizableFieldContext.EXPOSURE, "locationGeneral");
64+
65+
private final CustomizableFieldContext context;
66+
/**
67+
* Stable key stored in the database and used as the Vaadin layout location ID.
68+
*/
69+
private final String key;
70+
71+
CustomizableFieldGroup(CustomizableFieldContext context, String key) {
72+
this.context = context;
73+
this.key = key;
74+
}
75+
76+
/**
77+
* The {@link CustomizableFieldContext} this group belongs to.
78+
*/
79+
public CustomizableFieldContext getContext() {
80+
return context;
81+
}
82+
83+
/**
84+
* Stable string key used as the database-stored value and as the Vaadin layout location ID.
85+
*/
86+
public String getKey() {
87+
return key;
88+
}
89+
90+
/**
91+
* Returns all groups that belong to the given context.
92+
*/
93+
public static List<CustomizableFieldGroup> getGroupsForContext(CustomizableFieldContext context) {
94+
List<CustomizableFieldGroup> result = new ArrayList<>();
95+
for (CustomizableFieldGroup group : values()) {
96+
if (group.context == context) {
97+
result.add(group);
98+
}
99+
}
100+
return result;
101+
}
102+
103+
/**
104+
* Looks up a group by its stable {@link #key}, returning {@code null} if not found.
105+
*/
106+
public static CustomizableFieldGroup fromKey(String key) {
107+
if (key == null) {
108+
return null;
109+
}
110+
for (CustomizableFieldGroup group : values()) {
111+
if (group.key.equals(key)) {
112+
return group;
113+
}
114+
}
115+
return null;
116+
}
117+
}
Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
/*
2+
* SORMAS® - Surveillance Outbreak Response Management & Analysis System
3+
* Copyright © 2016-2026 SORMAS Foundation gGmbH
4+
* This program is free software: you can redistribute it and/or modify
5+
* it under the terms of the GNU General Public License as published by
6+
* the Free Software Foundation, either version 3 of the License, or
7+
* (at your option) any later version.
8+
* This program is distributed in the hope that it will be useful,
9+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
10+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11+
* GNU General Public License for more details.
12+
* You should have received a copy of the GNU General Public License
13+
* along with this program. If not, see <https://www.gnu.org/licenses/>.
14+
*/
15+
16+
package de.symeda.sormas.api.customizablefield;
17+
18+
import de.symeda.sormas.api.utils.IgnoreForUrl;
19+
import de.symeda.sormas.api.utils.criteria.BaseCriteria;
20+
21+
/**
22+
* Criteria for filtering customizable field metadata in admin views.
23+
*/
24+
public class CustomizableFieldMetadataCriteria extends BaseCriteria {
25+
26+
private static final long serialVersionUID = 1L;
27+
28+
private String freeTextFilter;
29+
private CustomizableFieldContext contextClass;
30+
private CustomizableFieldType fieldType;
31+
private Boolean active;
32+
33+
public String getFreeTextFilter() {
34+
return freeTextFilter;
35+
}
36+
37+
public CustomizableFieldMetadataCriteria freeTextFilter(String freeTextFilter) {
38+
this.freeTextFilter = freeTextFilter;
39+
return this;
40+
}
41+
42+
@IgnoreForUrl
43+
public CustomizableFieldContext getContextClass() {
44+
return contextClass;
45+
}
46+
47+
public void setContextClass(CustomizableFieldContext contextClass) {
48+
this.contextClass = contextClass;
49+
}
50+
51+
@IgnoreForUrl
52+
public CustomizableFieldType getFieldType() {
53+
return fieldType;
54+
}
55+
56+
public void setFieldType(CustomizableFieldType fieldType) {
57+
this.fieldType = fieldType;
58+
}
59+
60+
@IgnoreForUrl
61+
public Boolean getActive() {
62+
return active;
63+
}
64+
65+
public void setActive(Boolean active) {
66+
this.active = active;
67+
}
68+
}

0 commit comments

Comments
 (0)