Skip to content

Conversation

@KochTobi
Copy link
Member

Changes the UI for experimental variable edit and creation.
Allows for

  • renaming of experimental variables
  • adding levels to existing experimental variables
  • removing unused levels from experimental variables
  • locking of input fields that cannot be edited.

KochTobi added 30 commits June 11, 2025 12:40
…perimental-variable-functions

# Conflicts:
#	project-management/src/main/java/life/qbic/projectmanagement/application/api/AsyncProjectService.java
#	project-management/src/main/java/life/qbic/projectmanagement/application/api/AsyncProjectServiceImpl.java
#	user-interface/src/main/java/life/qbic/datamanager/views/projects/project/experiments/experiment/ExperimentDetailsComponent.java
#	user-interface/src/main/java/life/qbic/datamanager/views/projects/project/experiments/experiment/components/ExperimentalVariableRowLayout.java
Replace `.vertical-list` by `.flex-vertical .width-full`
Replace `.trailing-margin-large` by `.margin-bottom-07`
Replace `.trailing-margin-normal` by `.margin-bottom-05`
Replace `.trailing-margin-small` by `.margin-bottom-03`
removes Speculative Generality
…perimental-variable-functions

# Conflicts:
#	project-management/src/main/java/life/qbic/projectmanagement/application/api/AsyncProjectService.java
#	user-interface/frontend/themes/datamanager/components/all.css
#	user-interface/src/main/bundles/dev.bundle
#	user-interface/src/main/java/life/qbic/datamanager/views/general/dialog/DialogBody.java
#	user-interface/src/main/java/life/qbic/datamanager/views/general/dialog/DialogSection.java
…perimental-variable-functions

# Conflicts:
#	user-interface/src/main/bundles/dev.bundle
KochTobi and others added 3 commits October 6, 2025 11:55
When editing a duplicated variable name, the error message is removed.
@KochTobi KochTobi requested a review from sven1103 October 6, 2025 10:39
KochTobi and others added 6 commits October 6, 2025 12:40
…perimental-variable-functions

# Conflicts:
#	user-interface/src/main/bundles/dev.bundle
Co-authored-by: Shraddha Pawar <[email protected]>
Co-authored-by: Shraddha Pawar <[email protected]>
Copy link
Contributor

@sven1103 sven1103 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Your are getting there, thank you for addressing quite some change requests already.

I still have concerns about some implementations and left comments there.


/**
* Queries all available experimental variables for a given experiment.
* Returns existing experimental variables in lexigraphical order of the variable name.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

typo in lexicographical

* @param experimentId the experiment identifier of the experiment to get the variables from
* @return a {@link Flux<ExperimentalVariable>} emitting {@link ExperimentalVariable}s for the
* experiment.
* experiment in lexigraphical order of variable name.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

typo in lexicographical

.map(level -> (unit == null || unit.isBlank())
? ExperimentalValue.create(level)
: ExperimentalValue.create(level, unit))
.collect(Collectors.toList());
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Here a mutable list is created. I dont see the necessity for a mutable state here but risk for side effects. If there is no need for mutability the list shall be unmodifiable via toList()

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

addressed


/**
* Removes an experimental variable if possible.
* Removes an experimental variable if possible. Emits an experiment update domain event.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pro: if you reference the event class, so developers are happy when they need to subscribe to it in the service :)


/**
* Removes an experimental variable if possible.
* Removes an experimental variable if possible. Emits an experiment update domain event.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
* Removes an experimental variable if possible. Emits an experiment update domain event.
* Removes an experimental variable if possible. Emits an {@link ExperimentUpdatedEvent}.

.and(variableLevelsValidation);
}

void setInvalid(boolean invalid) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sure, but just because the framework does it, it is not good practise :) The flags can be easily overseen during debugging and implementation, clean code favours expressive semantics of methods over boolean configuration flags.

I kindly ask you to change it, it is 1 min work and introduces expressive semantics.

if (Optional.ofNullable(name.getErrorMessage())
.map(it -> !it.contains(errorMessage))
.orElse(true)) {
String composedErrorMessage = Optional.ofNullable(name.getErrorMessage())
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why is there a need to concat existing error messages? Also, the method JDs does not highlight that so this behaviour is opaque to the caller.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Overwriting the error message would make strong assumptions on the calling code (e.g. only invalid if name is blank or duplicated which cannot happen both at the same time)

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I still dont get it. You set the name invalid for one reason by the caller. Why is there hidden concatenation of previous error states?

@KochTobi KochTobi requested a review from sven1103 October 7, 2025 09:46
Copy link
Contributor

@sven1103 sven1103 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Still some concerns, in particular the rename experimental variables is troubling me.

return DragDropItem.this;
}

// Setting only the item as draggable element does not work
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

please create a follow up issue then and denote as a bug in our app and reference the Vaadin issue there. The code base shall stay clean.

dummy.restore(snapshot);
return dummy;
} catch (SnapshotRestorationException e) {
throw new IllegalStateException("Initial state not correctly set.", e);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

it is not an illegal state. It is an illegal argument at most or let the snapshot exception bubble up to the caller, which is the same class. Otherwise i dont see the point of having this semantic exception at all.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

addressed

if (Optional.ofNullable(name.getErrorMessage())
.map(it -> !it.contains(errorMessage))
.orElse(true)) {
String composedErrorMessage = Optional.ofNullable(name.getErrorMessage())
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I still dont get it. You set the name invalid for one reason by the caller. Why is there hidden concatenation of previous error states?

@KochTobi
Copy link
Member Author

KochTobi commented Oct 7, 2025

#1274 (comment)

A call to the method ensures that the field is set as invalid and that the provided error message is shown. It does not assume the field to be valid when calling the method neither does it assume that the provided error message is the only error message. Both is stated in the JavaDoc.

KochTobi and others added 3 commits October 7, 2025 15:21
Co-authored-by: Sven F. <[email protected]>
I removed the comment and we will encounter the issue again if and when we try to implement a drag handle. Tracking it with our own github issue is not necessary as maybe another solution is found at a future time.
Copy link
Contributor

@sven1103 sven1103 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I insist on some refactors since the are good safe guards and improve the overall robustness.

I also cannot see all the changes being made, although the comment was set to "addressed". I dont know where the update is cached, but I cant continue.

Copy link
Contributor

@sven1103 sven1103 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

One idea for the validation thingy

*
* @param errorMessage the error message to show.
*/
void setNameInvalid(@NonNull String errorMessage) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

OK, i think i get it now: elements of the variable row can be invalid for two different reasons: external validation logic and internal validation logic. And we must not override them.

But what happens if the external caller sets the name invalid for a reason, and the internal validation also already failed. Lets say after user input the external validation is fine, but the internal still fails. So currently the caller would use setNameValid which makes the name valid and removes ALL error messages, even the ones that might have come from internal validation.

I see tight coupling of the error message display and two different clients: an external and internal one. I think you need to wrap TextField into a small decorator that enables you to set invalid with message external and internal to keep track of where the change comes from. You can then refresh internally the valid state every time the API is called (either when external/internal validate or invalidate)

…ing-eperimental-variable-functions' into feature-1178/1178-implement-missing-eperimental-variable-functions
@KochTobi
Copy link
Member Author

KochTobi commented Oct 9, 2025

#1324

@KochTobi KochTobi merged commit d6318ab into development Oct 9, 2025
3 of 4 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Inform the user if a duplicate experimental variable was provided Implement missing experimental variable functions

4 participants