Skip to content

feat: Merge View (RDFA-344)#176

Open
kiph-soptim wants to merge 38 commits into
mainfrom
feature/RDFA-344-Cross-profile-diagrams
Open

feat: Merge View (RDFA-344)#176
kiph-soptim wants to merge 38 commits into
mainfrom
feature/RDFA-344-Cross-profile-diagrams

Conversation

@kiph-soptim

@kiph-soptim kiph-soptim commented Jun 11, 2026

Copy link
Copy Markdown
Collaborator

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

  • Tests added or updated (or not applicable)
  • Documentation updated (or not applicable)
  • No breaking changes introduced (or described in the summary above)
  • Commits are signed off (git commit -s) for DCO

Testing Notes

…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
kiph-soptim and others added 6 commits June 11, 2026 12:47
Co-authored-by: Copilot Autofix powered by AI <223894421+github-code-quality[bot]@users.noreply.github.com>
Signed-off-by: Philipp Kirchner <philipp.kirchner@soptim.de>
This reverts commit fd48b2d.
@kiph-soptim kiph-soptim marked this pull request as ready for review June 12, 2026 09:25

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 rema-soptim left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

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

Comment thread frontend/src/routes/UserSettingDialog.svelte
Comment thread frontend/src/routes/mainpage/packageNavigation/ClassEntry.svelte Outdated
Comment thread frontend/src/lib/rendering/svelteflow/svelteFlowWrapper.svelte Outdated
Comment on lines 113 to 117
editorState.selectedClassType.updateValue(classType);
editorState.selectedDiagram.updateValue({
type: DiagramType.PACKAGE,
type: diagramType,
id: classNavEntry.parent?.id ?? "default",
});

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

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.

Comment thread frontend/src/lib/sharedState.svelte.js Outdated
Comment on lines +110 to +114
function shortName(uri) {
const match = uri.match(/[#/]([^#/]+)\/?$/);
return match ? match[1] : uri;
}
</script>

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Preferably use the existing uri class to separate the uri prefix from suffix to ensure consistent behavior across components.

Comment on lines +104 to +109
function snapshotOriginal() {
originalJson = JSON.stringify(
colorEntries.map(e => ({ graphURI: e.graphURI, color: e.color })),
);
}

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Why create a new map? Can't you just stringify the object directly? Same for the hasChanges derived

);

$effect(() => {
if (!datasetNavEntry.label) return;

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Is this case even possible? This would be a dataset without a label right?

Comment on lines +63 to 70
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>

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Here again, preferably use the existing uri class if possible to split prefix and suffix

Comment on lines +50 to +56
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;
}

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Use uri class

"Sending response to GET request: \"/api/datasets/{{}}/crossprofilediagram\" from \"{}\"",
datasetName,
originURL);
return databasePort.getCrossProfileDiagramUUID(datasetName).toString();

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

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()

Comment on lines +42 to +45
private String graphUri;

private String color;

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

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();

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

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?

Comment on lines +69 to +79
var crossProfileDiagram =
getCustomDiagramsUseCase.getCrossProfileDiagram(datasetName, true, true);

var cimCollection = converter.convert(crossProfileDiagram);

var result =
renderer.renderGlobalUML(
cimCollection,
datasetName,
databasePort.getCrossProfileDiagramUUID(datasetName));

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

These are 2 separate transactions. preferably they are all called in the same use case in one transaction

Comment on lines +75 to +98
/**
* 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);

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

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.

Comment on lines +102 to +111
new MergedClassDTO(
mergedUuid,
uri,
dto.getLabel(),
new ArrayList<>(),
new ArrayList<>(),
new ArrayList<>(),
new ArrayList<>(),
new ArrayList<>(),
new ArrayList<>()));

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

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());

Comment on lines 510 to 527
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);
}
});

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

maybe rewrite this foreach, since its kind of unreadable, because of the formatting

}

@Test
void getCrossProfileColors_returnsDTOFromUseCase() {

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

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;

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Rename this package name to match the regular expression '^[a-z_]+(.[a-z_][a-z0-9_])$'.


@Data
@AllArgsConstructor
public class GraphSourcedDTO<T> {

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Is this supposed to be named "GraphSourceDTO"?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants