-
Notifications
You must be signed in to change notification settings - Fork 0
Refactor annotation groups #563
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: develop-annotation-service
Are you sure you want to change the base?
Refactor annotation groups #563
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nice work. The new code definitely looks much better.
const style = { | ||
transform: CSS.Transform.toString(transform), | ||
transition, | ||
opacity: isDragged ? 0.3 : 1, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We could add the 0.3 as a variable draggedLayerListItemOpacity (or similar) to the theme.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same here with the style?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It is still open but maybe not necessary.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
From my point of view its fine, if you want to add it to the theme, feel free :D
Feat: Add new Annotation Group
Refactor annotation groups UI
Add and delete annotation groups
Refactor saving
I've noticed a problem with also existent in the Visian app deployment; when exporting a zip file with image layers and the "exclusive segmentations" setting enabled, there's a loss of information in the image layers. This shouldn't happen. Should I create a ticket for it or should we fix it in this branch? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Temporary review. Files not reviewed yet:
- layers.tsx
- save-popup.tsx
- annotation-group.ts
apps/editor/src/components/data-manager/confirmation-popup/confirmation-popup.props.ts
Show resolved
Hide resolved
apps/editor/src/components/editor/layers/draggable-group-list-item.tsx
Outdated
Show resolved
Hide resolved
const style = { | ||
transform: CSS.Transform.toString(transform), | ||
transition, | ||
opacity: isDragged ? 0.3 : 1, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same here with the style?
path.basename(filteredFiles.name, path.extname(filteredFiles.name)), | ||
this.getMetadataFromFile(filteredFiles), | ||
); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Couldn't you create a new method that accepts the filtered Files and call this method instead? Because you are using the same code down below again and this importFiles
method is already hard to understand, so I would suggest extracting the code.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
But it is basically one function call, I think to hide the is "annotationGroupId" in filteredFiles check is not the right way to refactor it and would make it even more obscure. But you are right the method really needs a refactoring.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Although it is only one function call, nevertheless these are 10 lines of code duplicated in the same, already hard to read method. I am insisting on this a bit, because we won't be the ones refactoring this whole method and should do our best to at least not make this method worse.
/** Sets the flag if the group experiences a change in the number of layers. */ | ||
setHasUnsavedChanges(value: boolean): void; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Okay, so but if the user made changes to a single layer (annotating something), this boolean is NOT set? Only, when the number of layers changed by deleting or adding some? In that case, I would probably rename the method to match the description.
Is this the method based on which we display or grey out the save button of the group?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Richard suggested that name, originally it was different. This flag indicates if there are changes in the number of layers of one group (e.g. caused by deletion or dragging). HasUnsavedChanges is a protected variable on annotation-groups usually you use hasChanges for one group, which checks the hasUnsavedChanges flag and the hasChanges flag for each layer of this group.
Additionally, we could set this flag on toggle the verification slider (then you would see the gray dot after toggle).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Okay thanks Tony for the explanation!
@Tonybodo @richartkeil what about setDidLayerNumberChange
? That would make it more obvious in the hasChanges
method of the annotation group, what factors trigger a change for an annotation group.
I like the idea with the verified slider. Am I right that as soon as the Annotation Group has changes, the popup is opened that asks the user how to proceed with the annotation group, if he wants to continue to the next task? This would enforce the behavior and make it more understandable 👍🏼
/** All layer ids in the group. */ | ||
layerIds: string[]; | ||
/** All layers in the group. */ | ||
layers: ILayer[]; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why must we store layers and layerIds in separate arrays? I think that makes it harder to synchronize them. Couldn't we instead add a layerIds method that filters the layers for their ids?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not 100% sure of this, but I think Richard and Konrad decided to do it this way.
When I remember correctly, layers and layerIds do not contain the same information. Annotation Groups for example also have a layerId for the layerMap but they are not a layer. Do you get the point?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Okay, I spoke with @richartkeil and he is himself unsure, why it was decided like that. He remembers some kind of limitation with the other proposed system, but will look into it and add his findings as a single sentence to the documenting comments, explaining the difference between the two arrays.
Thanks for your detailed review, even if many of the complained things have nothing to do with the initially pull request.
|
For the saving problems I'm very sorry I did a late change and use the path library but the pathextname was not correct for our format nii.gz and i didn't rechecked the case with .nii files after the merge. I think now should everything work. |
For the point with the verified, I don't have a clue what is the best workflow here. When you have an idea I can implement this. For instance, we could say on toggle you make changes on the annotation group an have to save again. Like this: public trySetIsVerified(value: boolean) { But we should handle it in a different merge request, because it is completely unrelated to the work here. |
@TimRiedel Thanks again for your review I currently pushed my changes for your suggestions and wrote something below your comments.
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for implementing many of my suggestions. This was a code review and a lot of the things are already better.
I will do the functionality review (bug testing) later this day.
path.basename(filteredFiles.name, path.extname(filteredFiles.name)), | ||
this.getMetadataFromFile(filteredFiles), | ||
); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Although it is only one function call, nevertheless these are 10 lines of code duplicated in the same, already hard to read method. I am insisting on this a bit, because we won't be the ones refactoring this whole method and should do our best to at least not make this method worse.
if (uniqueValues.size === 1 && uniqueValues.has(0)) { | ||
createdLayerId = await this.importAnnotation( | ||
{ ...imageWithUnit, name: `${image.name}` }, | ||
undefined, | ||
false, | ||
); | ||
if (files instanceof File) { | ||
this.addLayerToAnnotationGroup(createdLayerId, files); | ||
this.addMetadataToLayer(createdLayerId, files); | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same here, I think that could be extracted to a separate method as well, with a descriptive naming of what this code block is trying to achieve.
if ("annotationGroupId" in filteredFiles) { | ||
const typedFilteredFiles = filteredFiles as FileWithAnnotationGroup; | ||
const newUnzippedFiles = unzippedFiles.map((unzippedFile) => { | ||
const newFile = unzippedFile as FileWithAnnotationGroup; | ||
newFile.annotationGroupId = typedFilteredFiles.annotationGroupId; | ||
newFile.metadata = typedFilteredFiles.metadata; | ||
return newFile; | ||
}); | ||
await this.importFiles(newUnzippedFiles); | ||
} else { | ||
const fileName = path.basename(filteredFiles.name); | ||
await this.importFiles( | ||
this.createAnnotationGroup( | ||
unzippedFiles, | ||
fileName.slice(0, fileName.indexOf(".")), | ||
this.getMetadataFromFile(filteredFiles), | ||
), | ||
filteredFiles.name, | ||
this.getMetadataFromFile(filteredFiles), | ||
), | ||
filteredFiles.name, | ||
); | ||
); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same here, why not extract this to a method with a descriptive name?
/** All layer ids in the group. */ | ||
layerIds: string[]; | ||
/** All layers in the group. */ | ||
layers: ILayer[]; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Okay, I spoke with @richartkeil and he is himself unsure, why it was decided like that. He remembers some kind of limitation with the other proposed system, but will look into it and add his findings as a single sentence to the documenting comments, explaining the difference between the two arrays.
/** Sets the flag if the group experiences a change in the number of layers. */ | ||
setHasUnsavedChanges(value: boolean): void; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Okay thanks Tony for the explanation!
@Tonybodo @richartkeil what about setDidLayerNumberChange
? That would make it more obvious in the hasChanges
method of the annotation group, what factors trigger a change for an annotation group.
I like the idea with the verified slider. Am I right that as soon as the Annotation Group has changes, the popup is opened that asks the user how to proceed with the annotation group, if he wants to continue to the next task? This would enforce the behavior and make it more understandable 👍🏼
const style = { | ||
transform: CSS.Transform.toString(transform), | ||
transition, | ||
opacity: isDragged ? 0.3 : 1, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
From my point of view its fine, if you want to add it to the theme, feel free :D
I like the suggestion on letting the annotation group have changes when the verified button is toggled. Even if toggling it twice does not result in "no changes" anymore, this is better than not communicating to the user that these changes must be saved. Even in day-to-day programs like Word or VSCode: when you manually add some letters and then remove them with backspace, it still shows that you must save the document. Only if you hit "undo" the previous state is restored, but VISIAN does not allow this functionality currently. So the proposed workflow is fine 👍🏼
But doesn't this PR include the Issue and Branch "Refactor Saving"? In any case, I would definitely say it is in the scope of this PR, because this saving functionality was touched here to a great extent. Everything we do not do now will probably be on hold forever, because we are finishing this project soon. |
|
Sorry to hear that this is an old issue. I really thought at least BraTS is working entirely for import and export. Its up to you, either create a new issue or solve it right here. But I think we should fix that
Okay, lets create a new issue!
Sure, you can create a new issue, that is indeed a bit unrelated to this PR.
Lets fix this here as described in one of my previous comments! |
Closes #558.