Skip to content

Commit

Permalink
Enables multiple experimental group addition (#328)
Browse files Browse the repository at this point in the history
* Save current work progress

* Save work

* Save work

* Enable addition of multiple experimental groups

* Reload experimental groups after registration

* Enable experimental group edit

* Save current work

* Save the day

* Finish styling

* Clean up

* More cleanup work

* rename methods, extract methods

Co-authored-by: steffengreiner <[email protected]>

* Add all experimental groups or none

Co-authored-by: steffengreiner <[email protected]>

* rename method

Co-authored-by: steffengreiner <[email protected]>

* Exchange group input by existing component

* address code review

Co-authored-by: steffengreiner <[email protected]>

* Add JavaDoc

Co-authored-by: steffengreiner <[email protected]>

* rename method

Co-authored-by: steffengreiner <[email protected]>

* address review

* address review

* remove duplicate css, group css selectors

Co-authored-by: steffengreiner <[email protected]>

* remove unused css

Co-authored-by: steffengreiner <[email protected]>

---------

Co-authored-by: Tobias Koch <[email protected]>
Co-authored-by: steffengreiner <[email protected]>
  • Loading branch information
3 people authored Aug 3, 2023
1 parent 8c521f4 commit bb93893
Show file tree
Hide file tree
Showing 14 changed files with 659 additions and 312 deletions.
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
package life.qbic.projectmanagement.application;

import static java.util.Objects.requireNonNull;
import static life.qbic.logging.service.LoggerFactory.logger;

import life.qbic.application.commons.Result;
import life.qbic.logging.api.Logger;
import life.qbic.projectmanagement.application.sample.SampleInformationService;
import life.qbic.projectmanagement.domain.project.experiment.ExperimentId;
import org.springframework.beans.factory.annotation.Autowired;
Expand All @@ -18,6 +20,7 @@
@Service
public class DeletionService {

private static final Logger log = logger(DeletionService.class);
private final ExperimentInformationService experimentInformationService;

private final SampleInformationService sampleInformationService;
Expand Down Expand Up @@ -53,6 +56,20 @@ public Result<ExperimentId, ResponseCode> deleteAllExperimentalVariables(Experim
return Result.fromValue(id);
}

public Result<ExperimentId, ResponseCode> deleteAllExperimentalGroups(ExperimentId id) {
var queryResult = sampleInformationService.retrieveSamplesForExperiment(id);
if (queryResult.isError()) {
log.debug("experiment (%s) converting %s to %s".formatted(id, queryResult.getError(),
ResponseCode.QUERY_FAILED));
return Result.fromError(ResponseCode.QUERY_FAILED);
}
if (queryResult.isValue() && !queryResult.getValue().isEmpty()) {
return Result.fromError(ResponseCode.SAMPLES_STILL_ATTACHED_TO_EXPERIMENT);
}
experimentInformationService.deleteAllExperimentalGroups(id);
return Result.fromValue(id);
}

public enum ResponseCode {
SAMPLES_STILL_ATTACHED_TO_EXPERIMENT, QUERY_FAILED
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@
import java.util.List;
import java.util.Objects;
import java.util.Optional;
import java.util.Set;
import life.qbic.application.commons.ApplicationException;
import life.qbic.application.commons.Result;
import life.qbic.logging.api.Logger;
Expand Down Expand Up @@ -74,7 +73,7 @@ public Result<ExperimentalGroup, ResponseCode> addExperimentalGroupToExperiment(

Experiment activeExperiment = loadExperimentById(experimentId);
Result<ExperimentalGroup, ResponseCode> result = activeExperiment.addExperimentalGroup(
experimentalGroup.levels(), experimentalGroup.sampleSize());
experimentalGroup.levels(), experimentalGroup.replicateCount());
if (result.isValue()) {
experimentRepository.update(activeExperiment);
}
Expand All @@ -100,15 +99,9 @@ public List<ExperimentalGroup> experimentalGroupsFor(ExperimentId experimentId)
return experiment.getExperimentalGroups().stream().toList();
}

public void deleteExperimentGroup(ExperimentId experimentId, long groupId) {
Experiment experiment = loadExperimentById(experimentId);
experiment.removeExperimentGroup(groupId);
experimentRepository.update(experiment);
}

/**
* <b>ATTENTION!</b> This will remove all existing experimental variables and all defined experimental
* groups in a give experiment!
* <b>ATTENTION!</b> This will remove all existing experimental variables and all defined
* experimental groups in a give experiment!
*
* @param experimentId the experiment reference to delete the experimental variables from
* @since 1.0.0
Expand Down Expand Up @@ -261,19 +254,52 @@ public List<ExperimentalVariable> getVariablesOfExperiment(ExperimentId experime
}

/**
* Checks if the provided ExperimentId contains an experimental Group
* Deletes all experimental groups in a given experiment.
* <p>
* This method does not check if samples are already.
*
* @param id the experiment identifier of the experiment the experimental groups are going to be
* deleted.
* @since 1.0.0
*/
public void deleteAllExperimentalGroups(ExperimentId id) {
Experiment experiment = loadExperimentById(id);
experiment.removeAllExperimentalGroups();
experimentRepository.update(experiment);
}

/**
* Adds experimental groups to an experiment
*
* @param experimentId the {@link ExperimentId} of the {@link Experiment} which should be checked
* if it contains an {@link ExperimentalGroup}
* @return a boolean indicating if the experiment contains an {@link ExperimentalGroup}
* @param experimentId the experiment to add the groups to
* @param experimentalGroupDTOS the group information
* @return either the collection of added groups or an appropriate response code
*/
public boolean hasExperimentalGroup(ExperimentId experimentId) {
public Result<Collection<ExperimentalGroup>, ResponseCode> addExperimentalGroupsToExperiment(
ExperimentId experimentId, List<ExperimentalGroupDTO> experimentalGroupDTOS) {
Experiment experiment = loadExperimentById(experimentId);
return !experiment.getExperimentalGroups().isEmpty();
List<ExperimentalGroup> addedGroups = new ArrayList<>();
for (ExperimentalGroupDTO experimentalGroupDTO : experimentalGroupDTOS) {
Result<ExperimentalGroup, ResponseCode> result = experiment.addExperimentalGroup(
experimentalGroupDTO.levels(),
experimentalGroupDTO.replicateCount());
if (result.isError()) {
return Result.fromError(result.getError());
} else {
addedGroups.add(result.getValue());
}
}
experimentRepository.update(experiment);
return Result.fromValue(addedGroups);
}

public record ExperimentalGroupDTO(Set<VariableLevel> levels, int sampleSize) {
/**
* Information about an experimental group
*
* @param levels the levels in the condition of the group
* @param replicateCount the number of biological replicates
*/
public record ExperimentalGroupDTO(Collection<VariableLevel> levels, int replicateCount) {

}

}
Original file line number Diff line number Diff line change
Expand Up @@ -177,7 +177,7 @@ boolean isConditionDefined(Condition condition) {
}

Result<VariableName, Exception> addVariable(String variableName, List<ExperimentalValue> levels) {
if (levels.size() < 1) {
if (levels.isEmpty()) {
return Result.fromError(new IllegalArgumentException(
"No levels were defined for " + variableName));
}
Expand All @@ -197,7 +197,7 @@ Result<VariableName, Exception> addVariable(String variableName, List<Experiment
}

public void removeAllExperimentalVariables() throws IllegalStateException {
if (experimentalGroups.size() > 0) {
if (!experimentalGroups.isEmpty()) {
throw new IllegalStateException("Cannot delete experimental variables referenced by an experimental group.");
}
this.variables.clear();
Expand Down
21 changes: 20 additions & 1 deletion vaadinfrontend/frontend/themes/datamanager/components/card.css
Original file line number Diff line number Diff line change
Expand Up @@ -85,13 +85,32 @@
max-width: 300px;
}

.experimental-group-card-collection {
.experimental-group-card-collection .header {
justify-content: space-between;
display: flex;
}

.experimental-group-card-collection .content {
display: flex;
align-content: space-evenly;
flex-flow: row wrap;
gap: 1rem;
}

.experimental-group-card-collection .controls {
display: flex;
align-content: space-evenly;
flex-flow: row wrap;
gap: 0.5rem;
}

.experimental-group-card-collection {
display: block;
align-content: space-evenly;
flex-flow: row wrap;
gap: 1rem;
}

.experimental-group .header {
display: flex;
justify-content: space-between;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,3 +33,11 @@
.error-text {
color: var(--lumo-error-text-color);
}

vaadin-multi-select-combo-box::part(toggle-button)::before {
color: var(--lumo-primary-color);
}

vaadin-number-field::part(decrease-button), vaadin-number-field::part(increase-button) {
color: var(--lumo-primary-color);
}
66 changes: 51 additions & 15 deletions vaadinfrontend/frontend/themes/datamanager/components/dialog.css
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,22 @@
opacity: 0.05;
}

vaadin-dialog-overlay::part(content) {
padding: 1rem 4rem 3rem 4rem;
}

vaadin-dialog-overlay::part(footer) {
padding: 1rem 4rem 1rem 0;
}

vaadin-dialog-overlay::part(header) {
padding: 2rem 1rem 1rem 4rem;
}

vaadin-dialog-overlay::part(title) {
margin-inline-start: 0;
}

.batch-registration-dialog .stepper {
width: 100%;
height: 100%;
Expand Down Expand Up @@ -146,36 +162,55 @@ Used by both project creation and experiment creation dialog, thus the unique na
width: 66%;
}

.experiment-group-dialog .group-input {
width: 100%;
.experiment-group-dialog .number-field {
min-width: 175px;
}

.experiment-group-dialog .group-input .layout {
display: flex;
flex-direction: row;
gap: var(--lumo-space-m);
.experiment-group-dialog .experimental-group-entry {
display: grid;
grid: auto auto auto / 1fr 175px auto;
column-gap: 1rem;
align-items: baseline;
}

.experiment-group-dialog .group-input .layout .combo-box {
width: 100%;
.experiment-group-dialog vaadin-icon{
cursor: pointer;
color: var(--lumo-primary-color);
}

.experiment-group-dialog .group-input .layout .number-field {
width: 150px;
.experiment-group-dialog .header{
font-weight: bold;
}

.experiment-variable-dialog .content {
padding: var(--lumo-space-m);
gap: var(--lumo-space-m);
display: flex;
flex-direction: column;
}

.experiment-group-dialog .add-new-group-action {
display: flex;
column-gap: 1rem;
color: var(--lumo-primary-color)
}

.experiment-group-dialog .content {
display: grid;
gap: 1.5rem;
}

.experiment-group-dialog .content .group-collection {
display: grid;
gap: 1rem;
}


.experiment-group-dialog .add-new-group-action span{
cursor: pointer;
}

.experiment-variable-dialog .content .variables {
display: flex;
flex-direction: column;
gap: var(--lumo-space-m);
padding: var(--lumo-space-m);
}

.experiment-variable-dialog .content .variables .header {
Expand All @@ -185,9 +220,10 @@ Used by both project creation and experiment creation dialog, thus the unique na
.experiment-variable-dialog .content .row {
display: flex;
align-items: center;
gap: var(--lumo-space-m);
gap: var(--lumo-space-l);
}

.experiment-variable-dialog .content .row vaadin-icon {
cursor: pointer;
color: var(--lumo-primary-color);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
package life.qbic.datamanager.views.general;

import com.vaadin.flow.component.Component;
import com.vaadin.flow.component.ComponentEvent;
import java.io.Serial;

/**
* <b>Add event</b>
* <p>
* Indicates that a user wants to add information to a component
*
* @since 1.0.0
*/
public class AddEvent<T extends Component> extends ComponentEvent<T> {

@Serial
private static final long serialVersionUID = 9114334039868158765L;

/**
* Creates a new event using the given source and indicator whether the event originated from the
* client side or the server side.
*
* @param source the source component
* @param fromClient <code>true</code> if the event originated from the client
* side, <code>false</code> otherwise
*/
public AddEvent(T source, boolean fromClient) {
super(source, fromClient);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
package life.qbic.datamanager.views.general;


import com.vaadin.flow.component.Component;
import com.vaadin.flow.component.ComponentEvent;
import java.io.Serial;

/**
* <b>Edit Event</b>
*
* <p>Indicates that a user wants to edit information in a component.</p>
*
* @since 1.0.0
*/
public class EditEvent<T extends Component> extends ComponentEvent<T> {

@Serial
private static final long serialVersionUID = -1033061739347133861L;

/**
* Creates a new event using the given source and indicator whether the event originated from the
* client side or the server side.
*
* @param source the source component
* @param fromClient <code>true</code> if the event originated from the client
* side, <code>false</code> otherwise
*/
public EditEvent(T source, boolean fromClient) {
super(source, fromClient);
}
}
Loading

0 comments on commit bb93893

Please sign in to comment.