Skip to content

Commit 5ba0cd0

Browse files
authored
Merge pull request #13919 from SORMAS-Foundation/task-improve_external_message_display
#13904 - Added structured/detailed view for external message display
2 parents ab2aa0b + b491aed commit 5ba0cd0

5 files changed

Lines changed: 155 additions & 16 deletions

File tree

sormas-api/src/main/java/de/symeda/sormas/api/externalmessage/ExternalMessageAdapterFacade.java

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,18 @@
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+
116
package de.symeda.sormas.api.externalmessage;
217

318
import java.util.Date;
@@ -16,6 +31,7 @@ public interface ExternalMessageAdapterFacade {
1631
ExternalMessageResult<List<ExternalMessageDto>> getExternalMessages(Date since);
1732

1833
/**
34+
* The method should return the HTML source to display a structured/simpler view of the message.
1935
*
2036
* @param message
2137
* message to be converted
@@ -24,6 +40,18 @@ public interface ExternalMessageAdapterFacade {
2440
*/
2541
ExternalMessageResult<String> convertToHTML(ExternalMessageDto message);
2642

43+
/**
44+
* The method should return the HTML source to display a detailed view of the message.
45+
*
46+
* @param message
47+
* message to be converted
48+
* @return An ExternalMessageResult with a String that is a full/raw HTML representation of the message,
49+
* Falls back to {@link #convertToHTML(ExternalMessageDto)} by default.
50+
*/
51+
default ExternalMessageResult<String> convertToDetailedHTML(ExternalMessageDto message) {
52+
return convertToHTML(message);
53+
}
54+
2755
/**
2856
*
2957
* @param message

sormas-api/src/main/java/de/symeda/sormas/api/i18n/Captions.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1979,6 +1979,7 @@ public interface Captions {
19791979
String externalMessage_deleteNewlyCreatedCase = "externalMessage.deleteNewlyCreatedCase";
19801980
String externalMessage_deleteNewlyCreatedContact = "externalMessage.deleteNewlyCreatedContact";
19811981
String externalMessage_deleteNewlyCreatedEventParticipant = "externalMessage.deleteNewlyCreatedEventParticipant";
1982+
String externalMessage_detailedView = "externalMessage.detailedView";
19821983
String ExternalMessage_disease = "ExternalMessage.disease";
19831984
String ExternalMessage_diseaseVariant = "ExternalMessage.diseaseVariant";
19841985
String ExternalMessage_diseaseVariantDetails = "ExternalMessage.diseaseVariantDetails";
@@ -2012,6 +2013,7 @@ public interface Captions {
20122013
String ExternalMessage_sampleReceivedDate = "ExternalMessage.sampleReceivedDate";
20132014
String ExternalMessage_specimenCondition = "ExternalMessage.specimenCondition";
20142015
String ExternalMessage_status = "ExternalMessage.status";
2016+
String externalMessage_structuredView = "externalMessage.structuredView";
20152017
String ExternalMessage_surveillanceReport = "ExternalMessage.surveillanceReport";
20162018
String ExternalMessage_type = "ExternalMessage.type";
20172019
String ExternalMessageCriteria_birthDateFrom = "ExternalMessageCriteria.birthDateFrom";

sormas-api/src/main/resources/captions.properties

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1716,6 +1716,8 @@ infrastructureImportAllowOverwrite=Overwrite existing entries with imported data
17161716
#External Message
17171717
ExternalMessage=Message
17181718
ExternalMessage.labMessageDetails=Message details
1719+
externalMessage.structuredView=Structured view
1720+
externalMessage.detailedView=Detailed view
17191721
ExternalMessage.labSampleId=Lab sample ID
17201722
ExternalMessage.messageDateTime=Message date
17211723
ExternalMessage.personBirthDateDD=Day of birth

sormas-ui/src/main/java/de/symeda/sormas/ui/externalmessage/ExternalMessageForm.java

Lines changed: 114 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,18 @@
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+
116
package de.symeda.sormas.ui.externalmessage;
217

318
import static de.symeda.sormas.ui.utils.LayoutUtil.fluidRowLocs;
@@ -10,26 +25,41 @@
1025
import com.vaadin.ui.CustomLayout;
1126
import com.vaadin.ui.Label;
1227
import com.vaadin.ui.Panel;
13-
import com.vaadin.v7.data.util.converter.Converter;
28+
import com.vaadin.ui.TabSheet;
29+
import com.vaadin.ui.VerticalLayout;
1430

1531
import de.symeda.sormas.api.FacadeProvider;
1632
import de.symeda.sormas.api.externalmessage.ExternalMessageDto;
1733
import de.symeda.sormas.api.externalmessage.ExternalMessageResult;
34+
import de.symeda.sormas.api.i18n.Captions;
35+
import de.symeda.sormas.api.i18n.I18nProperties;
1836
import de.symeda.sormas.ui.utils.AbstractEditForm;
1937
import de.symeda.sormas.ui.utils.VaadinUiUtil;
2038

39+
@SuppressWarnings({
40+
"java:S110", // suppress sonar too many parents warning
41+
"java:S2160" // equals not overridden; value-equality is not needed for Vaadin form components
42+
})
2143
public class ExternalMessageForm extends AbstractEditForm<ExternalMessageDto> {
2244

2345
private static final long serialVersionUID = -3859401780981133265L;
2446

2547
//@formatter:off
2648
private static final String HTML_LAYOUT =
27-
fluidRowLocs(ExternalMessageDto.UUID, ExternalMessageDto.MESSAGE_DATE_TIME) +
49+
fluidRowLocs(ExternalMessageDto.UUID, ExternalMessageDto.MESSAGE_DATE_TIME) +
2850
fluidRowLocs(ExternalMessageDto.EXTERNAL_MESSAGE_DETAILS);
2951
//@formatter:on
3052

31-
private Panel detailsPanel;
53+
private TabSheet detailsTabSheet;
54+
private Panel structuredViewPanel;
55+
@SuppressWarnings("java:S1450") // referenced in addFields, tab listener and setValue - cannot be local
56+
private Panel detailedViewPanel;
57+
private VerticalLayout structuredViewContainer;
58+
private VerticalLayout detailedViewContainer;
59+
private boolean structuredViewLoaded;
60+
private boolean detailedViewLoaded;
3261

62+
@SuppressWarnings("java:S1948") // Logger is effectively serializable via its name
3363
private final Logger logger = LoggerFactory.getLogger(getClass());
3464

3565
public ExternalMessageForm() {
@@ -40,10 +70,44 @@ public ExternalMessageForm() {
4070
protected void addFields() {
4171
addFields(ExternalMessageDto.UUID, ExternalMessageDto.MESSAGE_DATE_TIME);
4272

43-
detailsPanel = new Panel();
44-
detailsPanel.setHeightFull();
45-
detailsPanel.addStyleName("lab-message-details");
46-
getContent().addComponent(detailsPanel, ExternalMessageDto.EXTERNAL_MESSAGE_DETAILS);
73+
structuredViewContainer = new VerticalLayout();
74+
structuredViewContainer.setMargin(false);
75+
structuredViewContainer.setSizeUndefined();
76+
77+
structuredViewPanel = new Panel();
78+
structuredViewPanel.setSizeFull();
79+
structuredViewPanel.addStyleName("lab-message-structured-view");
80+
structuredViewPanel.setContent(structuredViewContainer);
81+
82+
detailedViewContainer = new VerticalLayout();
83+
detailedViewContainer.setMargin(false);
84+
detailedViewContainer.setSizeUndefined();
85+
86+
detailedViewPanel = new Panel();
87+
detailedViewPanel.setSizeFull();
88+
detailedViewPanel.addStyleName("lab-message-detailed-view");
89+
detailedViewPanel.setContent(detailedViewContainer);
90+
91+
detailsTabSheet = new TabSheet();
92+
detailsTabSheet.setSizeFull();
93+
detailsTabSheet.addStyleName("lab-message-details");
94+
detailsTabSheet.addTab(structuredViewPanel, I18nProperties.getCaption(Captions.externalMessage_structuredView));
95+
detailsTabSheet.addTab(detailedViewPanel, I18nProperties.getCaption(Captions.externalMessage_detailedView));
96+
97+
detailsTabSheet.addSelectedTabChangeListener(event -> {
98+
ExternalMessageDto msg = getValue();
99+
if (msg == null) {
100+
return;
101+
}
102+
Component selected = event.getTabSheet().getSelectedTab();
103+
if (selected == structuredViewPanel) {
104+
loadStructuredView(msg);
105+
} else if (selected == detailedViewPanel) {
106+
loadDetailedView(msg);
107+
}
108+
});
109+
110+
getContent().addComponent(detailsTabSheet, ExternalMessageDto.EXTERNAL_MESSAGE_DETAILS);
47111
}
48112

49113
@Override
@@ -52,23 +116,57 @@ protected String createHtmlLayout() {
52116
}
53117

54118
@Override
55-
public void setValue(ExternalMessageDto externalMessage) throws ReadOnlyException, Converter.ConversionException {
119+
public void setValue(ExternalMessageDto externalMessage) {
56120
super.setValue(externalMessage);
57121
getFieldGroup().setReadOnly(true);
122+
structuredViewLoaded = false;
123+
detailedViewLoaded = false;
124+
structuredViewContainer.removeAllComponents();
125+
detailedViewContainer.removeAllComponents();
126+
loadStructuredView(externalMessage);
127+
detailsTabSheet.setSelectedTab(structuredViewPanel);
128+
}
129+
130+
private void loadStructuredView(ExternalMessageDto externalMessage) {
131+
if (structuredViewLoaded) {
132+
return;
133+
}
134+
try {
135+
ExternalMessageResult<String> result = FacadeProvider.getExternalLabResultsFacade().convertToHTML(externalMessage);
136+
if (result.isSuccess()) {
137+
CustomLayout layout = new CustomLayout();
138+
layout.setTemplateContents(result.getValue());
139+
structuredViewContainer.addComponent(layout);
140+
} else {
141+
structuredViewContainer.addComponent(createXmlDisplay(externalMessage.getExternalMessageDetails()));
142+
VaadinUiUtil.showWarningPopup(result.getError());
143+
}
144+
} catch (Exception e) {
145+
structuredViewContainer.addComponent(createXmlDisplay(externalMessage.getExternalMessageDetails()));
146+
logger.error(e.getMessage());
147+
}
148+
structuredViewLoaded = true;
149+
}
150+
151+
private void loadDetailedView(ExternalMessageDto externalMessage) {
152+
if (detailedViewLoaded) {
153+
return;
154+
}
58155
try {
59-
ExternalMessageResult<String> htmlConversionResult = FacadeProvider.getExternalLabResultsFacade().convertToHTML(externalMessage);
60-
if (htmlConversionResult.isSuccess()) {
61-
CustomLayout externalMessageDetails = new CustomLayout();
62-
externalMessageDetails.setTemplateContents(htmlConversionResult.getValue());
63-
detailsPanel.setContent(externalMessageDetails);
156+
ExternalMessageResult<String> result = FacadeProvider.getExternalLabResultsFacade().convertToDetailedHTML(externalMessage);
157+
if (result.isSuccess()) {
158+
CustomLayout layout = new CustomLayout();
159+
layout.setTemplateContents(result.getValue());
160+
detailedViewContainer.addComponent(layout);
64161
} else {
65-
detailsPanel.setContent(createXmlDisplay(externalMessage.getExternalMessageDetails()));
66-
VaadinUiUtil.showWarningPopup(htmlConversionResult.getError());
162+
detailedViewContainer.addComponent(createXmlDisplay(externalMessage.getExternalMessageDetails()));
163+
VaadinUiUtil.showWarningPopup(result.getError());
67164
}
68165
} catch (Exception e) {
69-
detailsPanel.setContent(createXmlDisplay(externalMessage.getExternalMessageDetails()));
166+
detailedViewContainer.addComponent(createXmlDisplay(externalMessage.getExternalMessageDetails()));
70167
logger.error(e.getMessage());
71168
}
169+
detailedViewLoaded = true;
72170
}
73171

74172
private Component createXmlDisplay(String xml) {

sormas-ui/src/main/webapp/VAADIN/themes/sormas/views/lab-message.scss

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,14 @@
55
user-select: text;
66
}
77

8+
.lab-message-structured-view .v-customlayout {
9+
min-width: 500px;
10+
}
11+
12+
.lab-message-detailed-view .v-customlayout {
13+
min-width: max-content;
14+
}
15+
816
.lab-message-processable,
917
.lab-message-slider {
1018
.lab-message-details {
@@ -20,6 +28,7 @@
2028
}
2129

2230
.no-required-border {
31+
2332
.v-textfield.v-required,
2433
.v-filterselect.v-required .v-filterselect-input,
2534
.v-customcomponent.v-required .v-datefield-textfield,

0 commit comments

Comments
 (0)