From ba17d92b7978f52dea6fde6a36ec09191800d779 Mon Sep 17 00:00:00 2001 From: Steffengreiner Date: Fri, 20 Dec 2024 14:39:10 +0100 Subject: [PATCH] Show comments for pooled and unpooled ProteomicsMeasurement and NGSMeasurment --- .../model/measurement/NGSMeasurement.java | 10 + .../measurement/ProteomicsMeasurement.java | 4 - ...ProteomicsSpecificMeasurementMetadata.java | 5 +- .../MeasurementDetailsComponent.java | 210 ++++++++++++------ .../measurements/MeasurementPresenter.java | 2 +- 5 files changed, 151 insertions(+), 80 deletions(-) diff --git a/project-management/src/main/java/life/qbic/projectmanagement/domain/model/measurement/NGSMeasurement.java b/project-management/src/main/java/life/qbic/projectmanagement/domain/model/measurement/NGSMeasurement.java index 2c8f7455d..8c6c6e1be 100644 --- a/project-management/src/main/java/life/qbic/projectmanagement/domain/model/measurement/NGSMeasurement.java +++ b/project-management/src/main/java/life/qbic/projectmanagement/domain/model/measurement/NGSMeasurement.java @@ -201,6 +201,16 @@ public void updateMethod(NGSMethodMetadata methodMetadata) { setMethod(methodMetadata); } + /** + * Convenience method to query if the measurement was derived from a pooled sample. + * + * @return true, if the measurement was performed on a pooled sample, else returns false + * @since 1.0.0 + */ + public boolean isPooledSampleMeasurement() { + return specificMetadata.size() > 1; + } + public MeasurementCode measurementCode() { return this.measurementCode; diff --git a/project-management/src/main/java/life/qbic/projectmanagement/domain/model/measurement/ProteomicsMeasurement.java b/project-management/src/main/java/life/qbic/projectmanagement/domain/model/measurement/ProteomicsMeasurement.java index eefc2a1fc..387387cb3 100644 --- a/project-management/src/main/java/life/qbic/projectmanagement/domain/model/measurement/ProteomicsMeasurement.java +++ b/project-management/src/main/java/life/qbic/projectmanagement/domain/model/measurement/ProteomicsMeasurement.java @@ -320,10 +320,6 @@ public int hashCode() { return measurementId != null ? measurementId.hashCode() : 0; } - public Optional comment() { - return Optional.empty(); - } - public Optional technicalReplicateName() { return Optional.ofNullable(technicalReplicateName); } diff --git a/project-management/src/main/java/life/qbic/projectmanagement/domain/model/measurement/ProteomicsSpecificMeasurementMetadata.java b/project-management/src/main/java/life/qbic/projectmanagement/domain/model/measurement/ProteomicsSpecificMeasurementMetadata.java index 65aa9a423..38a645b65 100644 --- a/project-management/src/main/java/life/qbic/projectmanagement/domain/model/measurement/ProteomicsSpecificMeasurementMetadata.java +++ b/project-management/src/main/java/life/qbic/projectmanagement/domain/model/measurement/ProteomicsSpecificMeasurementMetadata.java @@ -3,6 +3,7 @@ import jakarta.persistence.Column; import jakarta.persistence.Embeddable; import java.util.Objects; +import java.util.Optional; import life.qbic.projectmanagement.domain.model.sample.SampleId; /** @@ -80,8 +81,8 @@ public String fractionName() { return fractionName; } - public String comment() { - return comment; + public Optional comment() { + return comment.isBlank() ? Optional.empty() : Optional.of(comment); } } diff --git a/user-interface/src/main/java/life/qbic/datamanager/views/projects/project/measurements/MeasurementDetailsComponent.java b/user-interface/src/main/java/life/qbic/datamanager/views/projects/project/measurements/MeasurementDetailsComponent.java index d4c46a438..d4a3f2c92 100644 --- a/user-interface/src/main/java/life/qbic/datamanager/views/projects/project/measurements/MeasurementDetailsComponent.java +++ b/user-interface/src/main/java/life/qbic/datamanager/views/projects/project/measurements/MeasurementDetailsComponent.java @@ -70,10 +70,10 @@ @PermitAll public class MeasurementDetailsComponent extends PageArea implements Serializable { + public static final String CLICKABLE = "clickable"; @Serial private static final long serialVersionUID = 5086686432247130622L; private static final String DATE_TIME_FORMAT = "yyyy-MM-dd HH:mm"; - public static final String CLICKABLE = "clickable"; private final TabSheet registeredMeasurementsTabSheet = new TabSheet(); private final MultiSelectLazyLoadingGrid ngsMeasurementGrid = new MultiSelectLazyLoadingGrid<>(); private final MultiSelectLazyLoadingGrid proteomicsMeasurementGrid = new MultiSelectLazyLoadingGrid<>(); @@ -156,7 +156,7 @@ private void resetTabsInTabsheet() { } private void addMeasurementTab(GridLazyDataView gridLazyDataView) { - if(gridLazyDataView.getItems().findAny().isEmpty()) { + if (gridLazyDataView.getItems().findAny().isEmpty()) { return; } if (gridLazyDataView.getItem(0) instanceof ProteomicsMeasurement) { @@ -186,18 +186,18 @@ private void createNGSMeasurementGrid() { .setAutoWidth(true) .setFlexGrow(0); ngsMeasurementGrid.addComponentColumn(measurement -> { - if (measurement.samplePoolGroup().isEmpty()) { + if (!measurement.isPooledSampleMeasurement()) { return new Span( String.join(" ", groupSampleInfoIntoCodeAndLabel(measurement.measuredSamples()))); } - MeasurementPooledSamplesDialog measurementPooledSamplesDialog = new MeasurementPooledSamplesDialog( - measurement); - Icon expandIcon = VaadinIcon.EXPAND_SQUARE.create(); - expandIcon.addClassName("expand-icon"); - Span expandSpan = new Span(new Span("Pooled sample"), expandIcon); - expandSpan.addClassNames("sample-column-cell", CLICKABLE); - expandSpan.addClickListener(event -> measurementPooledSamplesDialog.open()); - return expandSpan; + return createNGSPooledSampleComponent(measurement); + }) + .setTooltipGenerator(measurement -> { + if (!measurement.isPooledSampleMeasurement()) { + return String.join(" ", groupSampleInfoIntoCodeAndLabel(measurement.measuredSamples())); + } else { + return ""; + } }) .setHeader("Samples") .setAutoWidth(true); @@ -242,6 +242,28 @@ private void createNGSMeasurementGrid() { ngsMeasurement -> asClientLocalDateTime(ngsMeasurement.registrationDate()) .format(DateTimeFormatter.ofPattern(DATE_TIME_FORMAT))) .setAutoWidth(true); + ngsMeasurementGrid.addComponentColumn(measurement -> { + if (!measurement.isPooledSampleMeasurement()) { + Span singularComment = new Span(); + singularComment.setText( + measurement.specificMeasurementMetadata().stream().findFirst().orElseThrow().comment() + .orElse("")); + return singularComment; + } else { + return createNGSPooledSampleComponent(measurement); + } + }) + .setHeader("Comment") + .setTooltipGenerator(measurement -> { + if (!measurement.isPooledSampleMeasurement()) { + return measurement.specificMeasurementMetadata().stream().findFirst().orElseThrow() + .comment() + .orElse(""); + } else { + return ""; + } + }) + .setAutoWidth(true); GridLazyDataView ngsGridDataView = ngsMeasurementGrid.setItems(query -> { List sortOrders = query.getSortOrders().stream().map( it -> new SortOrder(it.getSorted(), it.getDirection().equals(SortDirection.ASCENDING))) @@ -281,16 +303,15 @@ private void createProteomicsGrid() { return new Span( String.join(" ", groupSampleInfoIntoCodeAndLabel(measurement.measuredSamples()))); } - MeasurementPooledSamplesDialog measurementPooledSamplesDialog = new MeasurementPooledSamplesDialog( - measurement); - Icon expandIcon = VaadinIcon.EXPAND_SQUARE.create(); - expandIcon.addClassName("expand-icon"); - Span expandSpan = new Span(new Span("Pooled sample"), expandIcon); - expandSpan.addClassNames("sample-column-cell", CLICKABLE); - expandSpan.addClickListener(event -> measurementPooledSamplesDialog.open()); - return expandSpan; + return createProteomicsPooledSampleComponent(measurement); }) .setHeader("Samples") + .setTooltipGenerator(measurement -> { + if (!measurement.isPooledSampleMeasurement()) { + return String.join(" ", groupSampleInfoIntoCodeAndLabel(measurement.measuredSamples())); + } + return ""; + }) .setAutoWidth(true); proteomicsMeasurementGrid.addComponentColumn( proteomicsMeasurement -> renderOrganisation(proteomicsMeasurement.organisation())) @@ -339,9 +360,25 @@ private void createProteomicsGrid() { .setTooltipGenerator(measurement -> asClientLocalDateTime(measurement.registrationDate()) .format(DateTimeFormatter.ofPattern(DATE_TIME_FORMAT))) .setAutoWidth(true); - proteomicsMeasurementGrid.addColumn(measurement -> measurement.comment().orElse("")) + proteomicsMeasurementGrid.addComponentColumn(measurement -> { + if (!measurement.isPooledSampleMeasurement()) { + Span singularComment = new Span(); + singularComment.setText( + measurement.specificMetadata().stream().findFirst().orElseThrow().comment().orElse("")); + return singularComment; + } else { + return createProteomicsPooledSampleComponent(measurement); + } + }) .setHeader("Comment") - .setTooltipGenerator(measurement -> measurement.comment().orElse("")) + .setTooltipGenerator(measurement -> { + if (!measurement.isPooledSampleMeasurement()) { + return measurement.specificMetadata().stream().findFirst().orElseThrow().comment() + .orElse(""); + } else { + return ""; + } + }) .setAutoWidth(true); GridLazyDataView proteomicsGridDataView = proteomicsMeasurementGrid.setItems( query -> { @@ -349,11 +386,11 @@ private void createProteomicsGrid() { it -> new SortOrder(it.getSorted(), it.getDirection().equals(SortDirection.ASCENDING))) .collect(Collectors.toList()); - sortOrders.add(SortOrder.of("measurementCode").ascending()); - return measurementService.findProteomicsMeasurements(searchTerm, - context.experimentId().orElseThrow(), - query.getOffset(), query.getLimit(), sortOrders, context.projectId().orElseThrow()) - .stream(); + sortOrders.add(SortOrder.of("measurementCode").ascending()); + return measurementService.findProteomicsMeasurements(searchTerm, + context.experimentId().orElseThrow(), + query.getOffset(), query.getLimit(), sortOrders, context.projectId().orElseThrow()) + .stream(); }); proteomicsGridDataView @@ -365,6 +402,28 @@ private void createProteomicsGrid() { measurementsGridDataViews.add(proteomicsGridDataView); } + private Span createProteomicsPooledSampleComponent(ProteomicsMeasurement measurement) { + MeasurementPooledSamplesDialog measurementPooledSamplesDialog = new MeasurementPooledSamplesDialog( + measurement); + Icon expandIcon = VaadinIcon.EXPAND_SQUARE.create(); + expandIcon.addClassName("expand-icon"); + Span expandSpan = new Span(new Span("Pooled sample"), expandIcon); + expandSpan.addClassNames("sample-column-cell", CLICKABLE); + expandSpan.addClickListener(event -> measurementPooledSamplesDialog.open()); + return expandSpan; + } + + private Span createNGSPooledSampleComponent(NGSMeasurement measurement) { + MeasurementPooledSamplesDialog measurementPooledSamplesDialog = new MeasurementPooledSamplesDialog( + measurement); + Icon expandIcon = VaadinIcon.EXPAND_SQUARE.create(); + expandIcon.addClassName("expand-icon"); + Span expandSpan = new Span(new Span("Pooled sample"), expandIcon); + expandSpan.addClassNames("sample-column-cell", CLICKABLE); + expandSpan.addClickListener(event -> measurementPooledSamplesDialog.open()); + return expandSpan; + } + private void updateSelectedMeasurementsInfo(boolean isFromClient) { listeners.forEach(listener -> listener.onComponentEvent( new MeasurementSelectionChangedEvent(this, isFromClient))); @@ -473,6 +532,54 @@ public MeasurementSelectionChangedEvent(MeasurementDetailsComponent source, } } + public static class MeasurementTechnologyTab extends Tab { + + private final Span countBadge; + private final Span technologyNameComponent; + private final String technology; + + public MeasurementTechnologyTab(String technology, int measurementCount) { + this.technology = technology; + technologyNameComponent = new Span(); + this.countBadge = createBadge(); + Span sampleCountComponent = new Span(); + sampleCountComponent.add(countBadge); + this.add(technologyNameComponent, sampleCountComponent); + setTechnologyName(technology); + setMeasurementCount(measurementCount); + addClassName("tab-with-count"); + } + + /** + * Helper method for creating a badge. + */ + private static Span createBadge() { + Tag tag = new Tag(String.valueOf(0)); + tag.setTagColor(TagColor.CONTRAST); + return tag; + } + + public String getTabLabel() { + return technology; + } + + /** + * Setter method for specifying the number of measurements of the technology type shown in this + * component + * + * @param measurementCount number of samples associated with the experiment shown in this + * component + */ + public void setMeasurementCount(int measurementCount) { + countBadge.setText(String.valueOf(measurementCount)); + } + + public void setTechnologyName(String technologyName) { + this.technologyNameComponent.setText(technologyName); + } + + } + public class MeasurementPooledSamplesDialog extends Dialog { /** @@ -542,6 +649,10 @@ private void setPooledProteomicSampleDetails( .setHeader("Measurement Label") .setTooltipGenerator(ProteomicsSpecificMeasurementMetadata::label) .setAutoWidth(true); + sampleDetailsGrid.addColumn(metadata -> metadata.comment().orElse("")) + .setHeader("comment") + .setTooltipGenerator(metadata -> metadata.comment().orElse("")) + .setAutoWidth(true); sampleDetailsGrid.setItems(proteomicsSpecificMeasurementMetadata); add(sampleDetailsGrid); } @@ -611,51 +722,4 @@ private Span pooledMeasurementEntry(String propertyLabel, String propertyValue) } } - public static class MeasurementTechnologyTab extends Tab { - - private final Span countBadge; - private final Span technologyNameComponent; - private final String technology; - - public MeasurementTechnologyTab(String technology, int measurementCount) { - this.technology = technology; - technologyNameComponent = new Span(); - this.countBadge = createBadge(); - Span sampleCountComponent = new Span(); - sampleCountComponent.add(countBadge); - this.add(technologyNameComponent, sampleCountComponent); - setTechnologyName(technology); - setMeasurementCount(measurementCount); - addClassName("tab-with-count"); - } - - public String getTabLabel() { - return technology; - } - - /** - * Helper method for creating a badge. - */ - private static Span createBadge() { - Tag tag = new Tag(String.valueOf(0)); - tag.setTagColor(TagColor.CONTRAST); - return tag; - } - - /** - * Setter method for specifying the number of measurements of the technology type shown in - * this component - * - * @param measurementCount number of samples associated with the experiment shown in this component - */ - public void setMeasurementCount(int measurementCount) { - countBadge.setText(String.valueOf(measurementCount)); - } - - public void setTechnologyName(String technologyName) { - this.technologyNameComponent.setText(technologyName); - } - - } - } diff --git a/user-interface/src/main/java/life/qbic/datamanager/views/projects/project/measurements/MeasurementPresenter.java b/user-interface/src/main/java/life/qbic/datamanager/views/projects/project/measurements/MeasurementPresenter.java index 36caf5fd5..e98ec1e94 100644 --- a/user-interface/src/main/java/life/qbic/datamanager/views/projects/project/measurements/MeasurementPresenter.java +++ b/user-interface/src/main/java/life/qbic/datamanager/views/projects/project/measurements/MeasurementPresenter.java @@ -51,7 +51,7 @@ private static ProteomicsMeasurementEntry convertProteomicsMeasurement( measurement.lcmsMethod(), measurement.labelType(), specificMeasurementMetadata.label(), - specificMeasurementMetadata.comment()); + specificMeasurementMetadata.comment().orElse("")); } private static NGSMeasurementEntry convertNGSMeasurement(NGSMeasurement measurement,