diff --git a/dsf-fhir/dsf-fhir-server/src/main/java/dev/dsf/fhir/adapter/AbstractSearchSet.java b/dsf-fhir/dsf-fhir-server/src/main/java/dev/dsf/fhir/adapter/AbstractSearchSet.java index 9fdf9167d..817047c27 100644 --- a/dsf-fhir/dsf-fhir-server/src/main/java/dev/dsf/fhir/adapter/AbstractSearchSet.java +++ b/dsf-fhir/dsf-fhir-server/src/main/java/dev/dsf/fhir/adapter/AbstractSearchSet.java @@ -3,6 +3,7 @@ import java.net.URI; import java.net.URISyntaxException; import java.util.List; +import java.util.Objects; import java.util.function.BiConsumer; import java.util.function.Function; import java.util.function.Predicate; @@ -18,6 +19,7 @@ import org.hl7.fhir.r4.model.Identifier; import org.hl7.fhir.r4.model.OperationOutcome; import org.hl7.fhir.r4.model.OperationOutcome.OperationOutcomeIssueComponent; +import org.hl7.fhir.r4.model.Reference; import org.hl7.fhir.r4.model.Resource; import org.hl7.fhir.r4.model.StringType; import org.hl7.fhir.r4.model.Task.ParameterComponent; @@ -168,6 +170,19 @@ private int getCount(MultivaluedMap params, int defaultPageCount return defaultPageCount; } + protected final String getIdentifierValue(D resource, Function hasIdentifier, + Function getIdentifier) + { + Objects.requireNonNull(hasIdentifier, "hasIdentifier"); + Objects.requireNonNull(getIdentifier, "getIdentifier"); + + if (!hasIdentifier.apply(resource)) + return ""; + + Identifier identifier = getIdentifier.apply(resource); + return (identifier != null && identifier.hasValue()) ? identifier.getValue() : ""; + } + protected final String getIdentifierValues(D resource, Function hasIdentifier, Function> getIdentifier, String identifierSystem) { @@ -184,6 +199,24 @@ protected final String getIdentifierValues(D resource return filteredIdentifiers.get(0) + (filteredIdentifiers.size() > 1 ? ", ..." : ""); } + protected final String getReferenceIdentifierValues(D resource, + Function hasReference, Function> getReference) + { + Objects.requireNonNull(hasReference, "hasReference"); + Objects.requireNonNull(getReference, "getReference"); + + if (!hasReference.apply(resource)) + return ""; + + List identifiers = getReference.apply(resource).stream().filter(Reference::hasIdentifier) + .map(Reference::getIdentifier).filter(Identifier::hasValue).map(Identifier::getValue).toList(); + + if (identifiers.isEmpty()) + return ""; + + return identifiers.get(0) + (identifiers.size() > 1 ? ", ..." : ""); + } + protected final String getResourceType(IIdType id) { return id != null ? id.getResourceType() : ""; diff --git a/dsf-fhir/dsf-fhir-server/src/main/java/dev/dsf/fhir/adapter/AbstractThymeleafContext.java b/dsf-fhir/dsf-fhir-server/src/main/java/dev/dsf/fhir/adapter/AbstractThymeleafContext.java index 375da51fb..e68abce08 100644 --- a/dsf-fhir/dsf-fhir-server/src/main/java/dev/dsf/fhir/adapter/AbstractThymeleafContext.java +++ b/dsf-fhir/dsf-fhir-server/src/main/java/dev/dsf/fhir/adapter/AbstractThymeleafContext.java @@ -18,8 +18,10 @@ import org.hl7.fhir.r4.model.DecimalType; import org.hl7.fhir.r4.model.Enumeration; import org.hl7.fhir.r4.model.Identifier; +import org.hl7.fhir.r4.model.InstantType; import org.hl7.fhir.r4.model.IntegerType; import org.hl7.fhir.r4.model.PrimitiveType; +import org.hl7.fhir.r4.model.Reference; import org.hl7.fhir.r4.model.Resource; import org.hl7.fhir.r4.model.StringType; import org.hl7.fhir.r4.model.UriType; @@ -134,6 +136,12 @@ protected final String getDateTime(E resource, Predicate has return formatDateTime(getValue(resource, hasDateTime, getDateTime)); } + protected final String getInstant(E resource, Predicate hasInstant, + Function getInstant) + { + return formatDateTime(getValue(resource, hasInstant, getInstant)); + } + protected final Boolean getBoolean(E resource, Predicate hasBoolean, Function getBoolean) { @@ -175,6 +183,19 @@ protected final String getEnumeration(E resource, Predicate return e != null && e.hasCode() ? e.getCode() : null; } + protected final ElementSystemValue getIdentifier(E resource, Predicate hasIdentifier, + Function getIdentifier) + { + Objects.requireNonNull(hasIdentifier, "hasIdentifier"); + Objects.requireNonNull(getIdentifier, "getIdentifier"); + + if (resource == null || !hasIdentifier.test(resource)) + return null; + + Identifier identifier = getIdentifier.apply(resource); + return identifier != null ? ElementSystemValue.from(identifier) : null; + } + protected final List getIdentifiers(E resource, Predicate hasIdentifier, Function> getIdentifier) { @@ -187,4 +208,20 @@ protected final List getIdentifiers(E resou List identifier = getIdentifier.apply(resource); return identifier != null ? identifier.stream().map(ElementSystemValue::from).toList() : null; } + + protected final List getReferenceIdentifiers(E resource, + Predicate hasReference, Function> getReference) + { + Objects.requireNonNull(hasReference, "hasReference"); + Objects.requireNonNull(getReference, "getReference"); + + if (resource == null || !hasReference.test(resource)) + return null; + + List references = getReference.apply(resource); + return references != null + ? references.stream().filter(Reference::hasIdentifier).map(Reference::getIdentifier) + .map(ElementSystemValue::from).toList() + : null; + } } diff --git a/dsf-fhir/dsf-fhir-server/src/main/java/dev/dsf/fhir/adapter/ResourceDocumentReference.java b/dsf-fhir/dsf-fhir-server/src/main/java/dev/dsf/fhir/adapter/ResourceDocumentReference.java new file mode 100644 index 000000000..ffc43767f --- /dev/null +++ b/dsf-fhir/dsf-fhir-server/src/main/java/dev/dsf/fhir/adapter/ResourceDocumentReference.java @@ -0,0 +1,50 @@ +package dev.dsf.fhir.adapter; + +import java.util.List; + +import org.hl7.fhir.r4.model.Attachment; +import org.hl7.fhir.r4.model.DocumentReference; + +public class ResourceDocumentReference extends AbstractResource +{ + private record AttachmentElement(String url, String contentType) + { + static AttachmentElement from(Attachment attachment) + { + return new AttachmentElement(attachment.getUrl(), attachment.getContentType()); + } + } + + private record Element(ElementSystemValue masterIdentifier, List identifier, + List author, String docStatus, String date, List attachment) + { + } + + public ResourceDocumentReference() + { + super(DocumentReference.class, AbstractResource.ActiveOrStatus.status(DocumentReference::hasStatusElement, + DocumentReference::getStatusElement)); + } + + @Override + protected Element toElement(DocumentReference resource) + { + ElementSystemValue masterIdentifier = getIdentifier(resource, DocumentReference::hasMasterIdentifier, + DocumentReference::getMasterIdentifier); + List identifier = getIdentifiers(resource, DocumentReference::hasIdentifier, + DocumentReference::getIdentifier); + + List author = getReferenceIdentifiers(resource, DocumentReference::hasAuthor, + DocumentReference::getAuthor); + String docStatus = resource.hasDocStatus() ? resource.getDocStatus().toCode() : null; + + String date = getInstant(resource, DocumentReference::hasDate, DocumentReference::getDateElement); + + List attachment = resource.getContent().stream() + .filter(DocumentReference.DocumentReferenceContentComponent::hasAttachment) + .map(DocumentReference.DocumentReferenceContentComponent::getAttachment).map(AttachmentElement::from) + .toList(); + + return new Element(masterIdentifier, nullIfEmpty(identifier), nullIfEmpty(author), docStatus, date, attachment); + } +} diff --git a/dsf-fhir/dsf-fhir-server/src/main/java/dev/dsf/fhir/adapter/SearchSetDocumentReference.java b/dsf-fhir/dsf-fhir-server/src/main/java/dev/dsf/fhir/adapter/SearchSetDocumentReference.java new file mode 100644 index 000000000..087677890 --- /dev/null +++ b/dsf-fhir/dsf-fhir-server/src/main/java/dev/dsf/fhir/adapter/SearchSetDocumentReference.java @@ -0,0 +1,30 @@ +package dev.dsf.fhir.adapter; + +import org.hl7.fhir.r4.model.DocumentReference; + +public class SearchSetDocumentReference extends AbstractSearchSet +{ + private record Row(ElementId id, String masterIdentifier, String author, String status, String docStatus, + String lastUpdated) + { + } + + public SearchSetDocumentReference(int defaultPageCount) + { + super(defaultPageCount, DocumentReference.class); + } + + @Override + protected Row toRow(ElementId id, DocumentReference resource) + { + String masterIdentifier = getIdentifierValue(resource, DocumentReference::hasMasterIdentifier, + DocumentReference::getMasterIdentifier); + String author = getReferenceIdentifierValues(resource, DocumentReference::hasAuthor, + DocumentReference::getAuthor); + String status = resource.hasStatus() ? resource.getStatus().toCode() : ""; + String docStatus = resource.hasDocStatus() ? resource.getDocStatus().toCode() : ""; + String lastUpdated = formatLastUpdated(resource); + + return new Row(id, masterIdentifier, author, status, docStatus, lastUpdated); + } +} diff --git a/dsf-fhir/dsf-fhir-server/src/main/java/dev/dsf/fhir/spring/config/AdapterConfig.java b/dsf-fhir/dsf-fhir-server/src/main/java/dev/dsf/fhir/spring/config/AdapterConfig.java index d6bcc2d05..0bf4d359d 100755 --- a/dsf-fhir/dsf-fhir-server/src/main/java/dev/dsf/fhir/spring/config/AdapterConfig.java +++ b/dsf-fhir/dsf-fhir-server/src/main/java/dev/dsf/fhir/spring/config/AdapterConfig.java @@ -18,6 +18,7 @@ import dev.dsf.fhir.adapter.ResourceActivityDefinition; import dev.dsf.fhir.adapter.ResourceBinary; import dev.dsf.fhir.adapter.ResourceCodeSystem; +import dev.dsf.fhir.adapter.ResourceDocumentReference; import dev.dsf.fhir.adapter.ResourceEndpoint; import dev.dsf.fhir.adapter.ResourceLibrary; import dev.dsf.fhir.adapter.ResourceMeasure; @@ -33,6 +34,7 @@ import dev.dsf.fhir.adapter.ResourceValueSet; import dev.dsf.fhir.adapter.SearchSetActivityDefinition; import dev.dsf.fhir.adapter.SearchSetBinary; +import dev.dsf.fhir.adapter.SearchSetDocumentReference; import dev.dsf.fhir.adapter.SearchSetEndpoint; import dev.dsf.fhir.adapter.SearchSetMeasureReport; import dev.dsf.fhir.adapter.SearchSetMetadataResource; @@ -70,7 +72,7 @@ public ThymeleafTemplateService thymeleafTemplateService() { List thymeleafContexts = List.of(new ResourceActivityDefinition(), new ResourceBinary(propertiesConfig.getDsfServerBaseUrl()), new ResourceCodeSystem(), - new ResourceEndpoint(), new ResourceLibrary(), new ResourceMeasure(), + new ResourceDocumentReference(), new ResourceEndpoint(), new ResourceLibrary(), new ResourceMeasure(), new ResourceMeasureReport(propertiesConfig.getDsfServerBaseUrl()), new ResourceNamingSystem(), new ResourceOrganizationAffiliation(), new ResourceOrganization(), new ResourceQuestionnaire(), new ResourceQuestionnaireResponse(), new ResourceStructureDefinition(), new ResourceSubscription(), @@ -78,6 +80,7 @@ public ThymeleafTemplateService thymeleafTemplateService() new SearchSetActivityDefinition(propertiesConfig.getDefaultPageCount()), new SearchSetBinary(propertiesConfig.getDefaultPageCount()), new SearchSetMetadataResource<>(propertiesConfig.getDefaultPageCount(), CodeSystem.class), + new SearchSetDocumentReference(propertiesConfig.getDefaultPageCount()), new SearchSetEndpoint(propertiesConfig.getDefaultPageCount()), new SearchSetMetadataResource<>(propertiesConfig.getDefaultPageCount(), Library.class), new SearchSetMetadataResource<>(propertiesConfig.getDefaultPageCount(), Measure.class), diff --git a/dsf-fhir/dsf-fhir-server/src/main/resources/fhir/static/bookmarks.js b/dsf-fhir/dsf-fhir-server/src/main/resources/fhir/static/bookmarks.js index 531b57ac4..0b4ad6561 100644 --- a/dsf-fhir/dsf-fhir-server/src/main/resources/fhir/static/bookmarks.js +++ b/dsf-fhir/dsf-fhir-server/src/main/resources/fhir/static/bookmarks.js @@ -129,6 +129,7 @@ function getInitialBookmarks() { '$ActivityDefinition': ['ActivityDefinition', "ActivityDefinition?_sort=status,url,version"], '$Binary': ['Binary'], '$CodeSystem': ['CodeSystem'], + '$DocumentReference': ['DocumentReference'], '$Endpoint': ['Endpoint'], '$NamingSystem': ['NamingSystem'], '$Library': ['Library'], diff --git a/dsf-fhir/dsf-fhir-server/src/main/resources/fhir/static/dsf.css b/dsf-fhir/dsf-fhir-server/src/main/resources/fhir/static/dsf.css index 9bad98cb2..4bcb9cf86 100644 --- a/dsf-fhir/dsf-fhir-server/src/main/resources/fhir/static/dsf.css +++ b/dsf-fhir/dsf-fhir-server/src/main/resources/fhir/static/dsf.css @@ -452,6 +452,18 @@ pre.lang-html { border-left-color: var(--color-row-border-grey); } +.bundle>#list>table tr[resource-type="DocumentReference"] td[status="current"] { + border-left-color: var(--color-row-border-green); +} + +.bundle>#list>table tr[resource-type="DocumentReference"] td[status="superseded"] { + border-left-color: var(--color-row-border-grey); +} + +.bundle>#list>table tr[resource-type="DocumentReference"] td[status="entered-in-error"] { + border-left-color: var(--color-row-border-red); +} + .bundle>#list>table tr[resource-type="Endpoint"] td[status="active"] { border-left-color: var(--color-row-border-green); } @@ -639,6 +651,21 @@ pre.lang-html { color: var(--color-info-grey); } +#resource[resource-type="DocumentReference"][status="current"] #base-data { + background-color: var(--color-info-background-green); + color: var(--color-info-green); +} + +#resource[resource-type="DocumentReference"][status="superseded"] #base-data { + background-color: var(--color-info-background-grey); + color: var(--color-info-grey); +} + +#resource[resource-type="DocumentReference"][status="entered-in-error"] #base-data { + background-color: var(--color-info-background-red); + color: var(--color-info-red); +} + #resource[resource-type="Endpoint"][status="active"] #base-data { background-color: var(--color-info-background-green); color: var(--color-info-green); @@ -800,6 +827,18 @@ pre.lang-html { fill: var(--color-info-grey); } +#resource[resource-type="DocumentReference"][status="current"] #base-data path { + fill: var(--color-info-green); +} + +#resource[resource-type="DocumentReference"][status="superseded"] #base-data path { + fill: var(--color-info-grey); +} + +#resource[resource-type="DocumentReference"][status="entered-in-error"] #base-data path { + fill: var(--color-info-red); +} + #resource[resource-type="Endpoint"][status="active"] #base-data path { fill: var(--color-info-green); } diff --git a/dsf-fhir/dsf-fhir-server/src/main/resources/fhir/template/resourceDocumentReference.html b/dsf-fhir/dsf-fhir-server/src/main/resources/fhir/template/resourceDocumentReference.html new file mode 100644 index 000000000..863df4063 --- /dev/null +++ b/dsf-fhir/dsf-fhir-server/src/main/resources/fhir/template/resourceDocumentReference.html @@ -0,0 +1,17 @@ + + + +
+
+ + + + + + + + +
+
+ + \ No newline at end of file diff --git a/dsf-fhir/dsf-fhir-server/src/main/resources/fhir/template/resourceElements.html b/dsf-fhir/dsf-fhir-server/src/main/resources/fhir/template/resourceElements.html index 4a2c252ca..64791bc6b 100644 --- a/dsf-fhir/dsf-fhir-server/src/main/resources/fhir/template/resourceElements.html +++ b/dsf-fhir/dsf-fhir-server/src/main/resources/fhir/template/resourceElements.html @@ -75,6 +75,21 @@ + +
+ + +
+ See json or xml for additional values. diff --git a/dsf-fhir/dsf-fhir-server/src/main/resources/fhir/template/searchsetDocumentReference.html b/dsf-fhir/dsf-fhir-server/src/main/resources/fhir/template/searchsetDocumentReference.html new file mode 100644 index 000000000..9863c6752 --- /dev/null +++ b/dsf-fhir/dsf-fhir-server/src/main/resources/fhir/template/searchsetDocumentReference.html @@ -0,0 +1,16 @@ + + + + + + + + + + + + + +
IDMaster IdentifierAuthorStatusDocument StatusLast Updated
ididentifiernamestatusdocStatuslastUpdated
+ + \ No newline at end of file