feat: Merge View (RDFA-344)#176
Conversation
…s-profile-diagrams # Conflicts: # frontend/src/routes/mainpage/packageNavigation/DatasetSection.svelte
…s-profile-diagrams # Conflicts: # backend/src/main/java/org/rdfarchitect/database/inmemory/GraphWithContext.java # backend/src/main/java/org/rdfarchitect/database/inmemory/GraphWithContextCollection.java # backend/src/main/java/org/rdfarchitect/database/inmemory/InMemoryDatabase.java # backend/src/main/java/org/rdfarchitect/database/inmemory/InMemoryDatabaseImpl.java # backend/src/main/java/org/rdfarchitect/database/inmemory/SessionDataStore.java # backend/src/main/java/org/rdfarchitect/services/diagrams/CustomDiagramService.java # backend/src/main/java/org/rdfarchitect/services/dl/select/QueryDiagramLayoutService.java # backend/src/main/java/org/rdfarchitect/services/dl/update/UpdateDiagramLayoutService.java # backend/src/main/java/org/rdfarchitect/services/dl/update/classlayout/UpdateClassLayoutService.java # frontend/src/lib/rendering/svelteflow/components/SvelteFlowClassContextMenu.svelte
Signed-off-by: Philipp Kirchner <philipp.kirchner@soptim.de>
|
|
||
| import java.util.List; | ||
|
|
||
| @EqualsAndHashCode(callSuper = true) |
|
|
||
| @EqualsAndHashCode(callSuper = true) | ||
| @Data | ||
| @SuperBuilder(toBuilder = true) |
| @Data | ||
| @AllArgsConstructor | ||
| public class CrossProfileDiagramColorDataDTO { | ||
| Map<String, String> graphColors; |
| private List<GraphSourcedDTO<AttributeDTO>> attributes; | ||
| private List<GraphSourcedDTO<EnumEntryDTO>> enumEntries; | ||
| private List<GraphSourcedDTO<AssociationPairDTO>> associationPairs; | ||
| private List<CIMSStereotype> stereotypes; |
| private List<GraphSourcedDTO<SuperClassDTO>> superClasses; | ||
| private List<GraphSourcedDTO<AttributeDTO>> attributes; | ||
| private List<GraphSourcedDTO<EnumEntryDTO>> enumEntries; | ||
| private List<GraphSourcedDTO<AssociationPairDTO>> associationPairs; |
| private List<ClassSourceDTO> sources; | ||
| private List<GraphSourcedDTO<SuperClassDTO>> superClasses; | ||
| private List<GraphSourcedDTO<AttributeDTO>> attributes; | ||
| private List<GraphSourcedDTO<EnumEntryDTO>> enumEntries; |
| private String label; | ||
| private List<ClassSourceDTO> sources; | ||
| private List<GraphSourcedDTO<SuperClassDTO>> superClasses; | ||
| private List<GraphSourcedDTO<AttributeDTO>> attributes; |
| private String classUri; | ||
| private String label; | ||
| private List<ClassSourceDTO> sources; | ||
| private List<GraphSourcedDTO<SuperClassDTO>> superClasses; |
| private UUID uuid; | ||
| private String classUri; | ||
| private String label; | ||
| private List<ClassSourceDTO> sources; |
rema-soptim
left a comment
There was a problem hiding this comment.
A few things i noticed, while using the new feature. This is not a complete test
- When opening a large merge view (full cgmes 2.4.15), the application is frozen for multiple seconds, before showing a loading animation for the diagram
- the same goes for expanding an (especially) collapsing the merged diagram section in the navigation
- clicked the merged view button once triggers a collapse or expand. instead this should happen on a double click.
- Deleting a Graph unselects the merged view instead of just reloading it.
- show Package Prefix setting only works in navigation not in the diagram
| editorState.selectedClassType.updateValue(classType); | ||
| editorState.selectedDiagram.updateValue({ | ||
| type: DiagramType.PACKAGE, | ||
| type: diagramType, | ||
| id: classNavEntry.parent?.id ?? "default", | ||
| }); |
There was a problem hiding this comment.
Wouldn't it make more sense to also add the selectedClassType into the selectedClassUUID and create a new selectedClass:
{
type: ...,
uuid: ...,
}
Since they are pretty much always updates together. Also this would reduce the risk of forgetting to reset/update only one of them since they must be kept in sync anyway.
| function shortName(uri) { | ||
| const match = uri.match(/[#/]([^#/]+)\/?$/); | ||
| return match ? match[1] : uri; | ||
| } | ||
| </script> |
There was a problem hiding this comment.
Preferably use the existing uri class to separate the uri prefix from suffix to ensure consistent behavior across components.
| function snapshotOriginal() { | ||
| originalJson = JSON.stringify( | ||
| colorEntries.map(e => ({ graphURI: e.graphURI, color: e.color })), | ||
| ); | ||
| } | ||
|
|
There was a problem hiding this comment.
Why create a new map? Can't you just stringify the object directly? Same for the hasChanges derived
| ); | ||
|
|
||
| $effect(() => { | ||
| if (!datasetNavEntry.label) return; |
There was a problem hiding this comment.
Is this case even possible? This would be a dataset without a label right?
| function getGraphLabel(graphURI) { | ||
| if (!graphURI) return graphURI; | ||
| const hashIndex = graphURI.lastIndexOf("#"); | ||
| const slashIndex = graphURI.lastIndexOf("/"); | ||
| const splitIndex = Math.max(hashIndex, slashIndex); | ||
| return splitIndex >= 0 ? graphURI.slice(splitIndex + 1) : graphURI; | ||
| } | ||
| </script> |
There was a problem hiding this comment.
Here again, preferably use the existing uri class if possible to split prefix and suffix
| function extractGraphLabel(graphUri) { | ||
| const hash = graphUri.lastIndexOf("#"); | ||
| const slash = graphUri.lastIndexOf("/"); | ||
| const idx = Math.max(hash, slash); | ||
| return idx >= 0 ? graphUri.substring(idx + 1) : graphUri; | ||
| } | ||
|
|
Signed-off-by: Philipp Kirchner <philipp.kirchner@soptim.de>
| "Sending response to GET request: \"/api/datasets/{{}}/crossprofilediagram\" from \"{}\"", | ||
| datasetName, | ||
| originURL); | ||
| return databasePort.getCrossProfileDiagramUUID(datasetName).toString(); |
There was a problem hiding this comment.
The method call should happen in between the 2 logs since this way the backend could log, that the result of the operation is sent to the frontend even if the program crashes inside databasePort.getCrossProfileDiagramUUID(datasetName).toString()
| private String graphUri; | ||
|
|
||
| private String color; | ||
|
|
There was a problem hiding this comment.
I think this is kind of questionable since the class is called CIMAssociation and cim resources do not have a color or graph attribute. I would suggest to create a deriving class specifically for rendering or something similar.
The same goes for the other CIMResource classes
|
|
||
| @Getter private final DiagramLayout diagramLayout = new DiagramLayout(); | ||
|
|
||
| @Getter private final UUID crossProfileDiagramUUID = UUID.randomUUID(); |
There was a problem hiding this comment.
There is only one CrossProfileDiagram right? Isn't this then not just the same as an uuid for the dataset or is there any reason why it's specific to the diagram?
| var crossProfileDiagram = | ||
| getCustomDiagramsUseCase.getCrossProfileDiagram(datasetName, true, true); | ||
|
|
||
| var cimCollection = converter.convert(crossProfileDiagram); | ||
|
|
||
| var result = | ||
| renderer.renderGlobalUML( | ||
| cimCollection, | ||
| datasetName, | ||
| databasePort.getCrossProfileDiagramUUID(datasetName)); | ||
|
|
There was a problem hiding this comment.
These are 2 separate transactions. preferably they are all called in the same use case in one transaction
| /** | ||
| * Returns the fixed UUID of the CrossProfileDiagram for the given dataset. | ||
| * | ||
| * @param datasetName literal dataset name | ||
| * @return UUID of the CrossProfileDiagram for the dataset | ||
| */ | ||
| UUID getCrossProfileDiagramUUID(String datasetName); | ||
|
|
||
| /** | ||
| * Returns the color of the given graph in the CrossProfileDiagram. | ||
| * | ||
| * @param graphIdentifier The identifier of the graph. | ||
| * @return The color as hex code of the graph. | ||
| */ | ||
| String getCrossProfileDiagramColor(GraphIdentifier graphIdentifier); | ||
|
|
||
| /** | ||
| * Sets the color of the given graph in the CrossProfileDiagram. | ||
| * | ||
| * @param graphIdentifier The identifier of the graph. | ||
| * @param color The color as hex code. | ||
| */ | ||
| void setCrossProfileDiagramColor(GraphIdentifier graphIdentifier, String color); | ||
|
|
There was a problem hiding this comment.
I feel like polluting the Dataset with feature specific methods is the wrong way. Instead, I think we should either store the colors in the graphWithContext, although I get that starting a transaction on all graphs, could be annoying.
Another way would be to handle this similar to the getDatasetDiagramLayout, which returns a new Object that hold the information about the crossProfileDiagram.
| new MergedClassDTO( | ||
| mergedUuid, | ||
| uri, | ||
| dto.getLabel(), | ||
| new ArrayList<>(), | ||
| new ArrayList<>(), | ||
| new ArrayList<>(), | ||
| new ArrayList<>(), | ||
| new ArrayList<>(), | ||
| new ArrayList<>())); |
There was a problem hiding this comment.
Explicitly initializing with a bunch of empty lists seems strange to me.
You could either make the lists final and add an @requiredargsconstructor,
create a builder or
annotate MergeClassDTO with @accessors(chain = true), set the lists to be an array list by default, and then create this object like this:
new MergedClassDTO();
.setUuid(mergedUuid)
.setClassUri(uri)
.setLabel(dto.getLabel());
| associationList.forEach( | ||
| cimAssociation -> { | ||
| var finalCimAssociation = cimAssociation; | ||
| if (cimCollection.getClasses().stream() | ||
| .anyMatch( | ||
| cimClass -> | ||
| cimClass.getUri() | ||
| .equals(cimAssociation.getRange().getUri()))) { | ||
| .equals( | ||
| finalCimAssociation | ||
| .getRange() | ||
| .getUri()))) { | ||
| cimAssociation = | ||
| cimAssociation.toBuilder() | ||
| .graphUri(graphIdentifier.graphUri()) | ||
| .build(); | ||
| cimCollection.getAssociations().add(cimAssociation); | ||
| } | ||
| }); |
There was a problem hiding this comment.
maybe rewrite this foreach, since its kind of unreadable, because of the formatting
| } | ||
|
|
||
| @Test | ||
| void getCrossProfileColors_returnsDTOFromUseCase() { |
There was a problem hiding this comment.
Rename tests to match the methodName_input_expectedResult convention, as used in other unit tests. this also goes for the other 3 new test classes
| * | ||
| */ | ||
|
|
||
| package org.rdfarchitect.api.dto.crossProfileDiagram; |
There was a problem hiding this comment.
Rename this package name to match the regular expression '^[a-z_]+(.[a-z_][a-z0-9_])$'.
|
|
||
| @Data | ||
| @AllArgsConstructor | ||
| public class GraphSourcedDTO<T> { |
There was a problem hiding this comment.
Is this supposed to be named "GraphSourceDTO"?
Summary
Adds the Merge View. In the merge view all classes of an dataset are merged based on their URI and displayed in one diagram.
Related Issues
Checklist
git commit -s) for DCOTesting Notes