Skip to content

Group participants by parent in plantuml structurizr seq diagrams #429

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

Open
wants to merge 10 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ public final Collection<Diagram> export(Workspace workspace) {
throw new IllegalArgumentException("A workspace must be provided.");
}

Collection<Diagram> diagrams = new ArrayList<>();
Collection<Diagram> diagrams = new ArrayList<>() ;

for (CustomView view : workspace.getViews().getCustomViews()) {
Diagram diagram = export(view);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ public abstract class AbstractPlantUMLExporter extends AbstractDiagramExporter {
public static final String PLANTUML_INCLUDES_PROPERTY = "plantuml.includes";
public static final String PLANTUML_ANIMATION_PROPERTY = "plantuml.animation";
public static final String PLANTUML_SEQUENCE_DIAGRAM_PROPERTY = "plantuml.sequenceDiagram";
public static final String PLANTUML_TEOZ_PROPERTY= "plantuml.teoz";

private static final double MAX_ICON_SIZE = 30.0;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,9 @@ public StructurizrPlantUMLExporter() {
@Override
protected void writeHeader(ModelView view, IndentingWriter writer) {
super.writeHeader(view, writer);
if (view instanceof DynamicView && renderAsTeozDiagram(view)) {
writer.writeLine("!pragma teoz true");
}
groupId = 0;

if (view instanceof DynamicView && renderAsSequenceDiagram(view)) {
Expand Down Expand Up @@ -176,37 +179,41 @@ protected void startGroupBoundary(ModelView view, String group, IndentingWriter
groupName = group.substring(group.lastIndexOf(groupSeparator) + groupSeparator.length());
}

if (!renderAsSequenceDiagram(view)) {
String color = "#cccccc";
String icon = "";

ElementStyle elementStyleForGroup = view.getViewSet().getConfiguration().getStyles().findElementStyle("Group:" + group);
ElementStyle elementStyleForAllGroups = view.getViewSet().getConfiguration().getStyles().findElementStyle("Group");
String color = "#cccccc";
String icon = "";

if (elementStyleForGroup != null && !StringUtils.isNullOrEmpty(elementStyleForGroup.getColor())) {
color = elementStyleForGroup.getColor();
} else if (elementStyleForAllGroups != null && !StringUtils.isNullOrEmpty(elementStyleForAllGroups.getColor())) {
color = elementStyleForAllGroups.getColor();
}
ElementStyle elementStyleForGroup = view.getViewSet().getConfiguration().getStyles().findElementStyle("Group:" + group);
ElementStyle elementStyleForAllGroups = view.getViewSet().getConfiguration().getStyles().findElementStyle("Group");

if (elementStyleForGroup != null && elementStyleHasSupportedIcon(elementStyleForGroup)) {
icon = elementStyleForGroup.getIcon();
} else if (elementStyleForAllGroups != null && elementStyleHasSupportedIcon(elementStyleForAllGroups)) {
icon = elementStyleForAllGroups.getColor();
}
if (elementStyleForGroup != null && !StringUtils.isNullOrEmpty(elementStyleForGroup.getColor())) {
color = elementStyleForGroup.getColor();
} else if (elementStyleForAllGroups != null && !StringUtils.isNullOrEmpty(elementStyleForAllGroups.getColor())) {
color = elementStyleForAllGroups.getColor();
}

if (!StringUtils.isNullOrEmpty(icon)) {
double scale = calculateIconScale(icon);
icon = "\\n\\n<img:" + icon + "{scale=" + scale + "}>";
}
if (elementStyleForGroup != null && elementStyleHasSupportedIcon(elementStyleForGroup)) {
icon = elementStyleForGroup.getIcon();
} else if (elementStyleForAllGroups != null && elementStyleHasSupportedIcon(elementStyleForAllGroups)) {
icon = elementStyleForAllGroups.getColor();
}

if (!StringUtils.isNullOrEmpty(icon)) {
double scale = calculateIconScale(icon);
icon = "\\n\\n<img:" + icon + "{scale=" + scale + "}>";
}
if (!renderAsSequenceDiagram(view)) {
writer.writeLine(String.format("rectangle \"%s%s\" <<group%s>> as group%s {", groupName, icon, groupId, groupId));
writer.indent();
writer.writeLine(String.format("skinparam RectangleBorderColor<<group%s>> %s", groupId, color));
writer.writeLine(String.format("skinparam RectangleFontColor<<group%s>> %s", groupId, color));
writer.writeLine(String.format("skinparam RectangleBorderStyle<<group%s>> dashed", groupId));

writer.writeLine();
} else {
//writer.writeLine(String.format("box \"%s%s\" <<group%s>> as group%s {", groupName, icon, groupId, groupId));
writer.writeLine(String.format("box \"%s%s\"", groupName, icon));

writer.indent();
}
}

Expand All @@ -216,13 +223,21 @@ protected void endGroupBoundary(ModelView view, IndentingWriter writer) {
writer.outdent();
writer.writeLine("}");
writer.writeLine();
} else {
writer.outdent();
writer.writeLine("end box");
writer.writeLine();
}
}

@Override
protected void startSoftwareSystemBoundary(ModelView view, SoftwareSystem softwareSystem, IndentingWriter writer) {
if (!renderAsSequenceDiagram(view)) {
writer.writeLine(String.format("rectangle \"%s\\n<size:10>%s</size>\" <<%s>> {", softwareSystem.getName(), typeOf(view, softwareSystem, true), idOf(softwareSystem)));
writer.indent();
} else {
writer.writeLine(String.format("box \"%s\n%s\"", softwareSystem.getName(), typeOf(view, softwareSystem, true)));

writer.indent();
}
}
Expand All @@ -233,13 +248,21 @@ protected void endSoftwareSystemBoundary(ModelView view, IndentingWriter writer)
writer.outdent();
writer.writeLine("}");
writer.writeLine();
} else {
writer.outdent();
writer.writeLine("end box");
writer.writeLine();
}
}

@Override
protected void startContainerBoundary(ModelView view, Container container, IndentingWriter writer) {
if (!renderAsSequenceDiagram(view)) {
writer.writeLine(String.format("rectangle \"%s\\n<size:10>%s</size>\" <<%s>> {", container.getName(), typeOf(view, container, true), idOf(container)));
writer.indent();
} else {
writer.writeLine(String.format("box \"%s\n%s\"", container.getName(), typeOf(view, container, true)));

writer.indent();
}
}
Expand All @@ -250,6 +273,10 @@ protected void endContainerBoundary(ModelView view, IndentingWriter writer) {
writer.outdent();
writer.writeLine("}");
writer.writeLine();
} else {
writer.outdent();
writer.writeLine("end box");
writer.writeLine();
}
}

Expand Down Expand Up @@ -296,27 +323,7 @@ protected void endDeploymentNodeBoundary(ModelView view, IndentingWriter writer)

@Override
public Diagram export(DynamicView view) {
if (renderAsSequenceDiagram(view)) {
IndentingWriter writer = new IndentingWriter();
writeHeader(view, writer);

Set<Element> elements = new LinkedHashSet<>();
for (RelationshipView relationshipView : view.getRelationships()) {
elements.add(relationshipView.getRelationship().getSource());
elements.add(relationshipView.getRelationship().getDestination());
}

for (Element element : elements) {
writeElement(view, element, writer);
}

writeRelationships(view, writer);
writeFooter(view, writer);

return createDiagram(view, writer.toString());
} else {
return super.export(view);
}
return super.export(view);
}

@Override
Expand Down Expand Up @@ -425,13 +432,14 @@ protected void writeRelationship(ModelView view, RelationshipView relationshipVi
}

writer.writeLine(
String.format("%s %s[%s]%s %s : %s",
String.format("%s %s[%s]%s %s : %s%s",
idOf(relationship.getSource()),
arrowStart,
style.getColor(),
arrowEnd,
idOf(relationship.getDestination()),
description));
description,
(StringUtils.isNullOrEmpty(technology) ? "" : "\\n<color:" + style.getColor() + "><size:8>[" + technology + "]</size>")));
} else {
boolean solid = style.getStyle() == LineStyle.Solid || false == style.getDashed();

Expand Down Expand Up @@ -629,4 +637,8 @@ protected boolean renderAsSequenceDiagram(ModelView view) {
return view instanceof DynamicView && "true".equalsIgnoreCase(getViewOrViewSetProperty(view, PLANTUML_SEQUENCE_DIAGRAM_PROPERTY, "false"));
}

protected boolean renderAsTeozDiagram(ModelView view) {
return view instanceof DynamicView && "true".equalsIgnoreCase(getViewOrViewSetProperty(view, PLANTUML_TEOZ_PROPERTY, "false"));
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ public void test_GroupsExample() throws Exception {

DOTExporter exporter = new DOTExporter();
Collection<Diagram> diagrams = exporter.export(workspace);
assertEquals(3, diagrams.size());
assertEquals(4, diagrams.size());

Diagram diagram = diagrams.stream().filter(md -> md.getKey().equals("SystemLandscape")).findFirst().get();
String expected = readFile(new File("./src/test/java/com/structurizr/export/dot/groups-SystemLandscape.dot"));
Expand All @@ -87,6 +87,10 @@ public void test_GroupsExample() throws Exception {
diagram = diagrams.stream().filter(md -> md.getKey().equals("Components")).findFirst().get();
expected = readFile(new File("./src/test/java/com/structurizr/export/dot/groups-Components.dot"));
assertEquals(expected, diagram.getDefinition());

diagram = diagrams.stream().filter(md -> md.getKey().equals("Dynamic")).findFirst().get();
expected = readFile(new File("./src/test/java/com/structurizr/export/dot/groups-Dynamic.dot"));
assertEquals(expected, diagram.getDefinition());
}

@Test
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,4 +32,5 @@ digraph {

3 -> 7 [id=13, label=<>, style="dashed", color="#707070", fontcolor="#707070"]
3 -> 8 [id=15, label=<>, style="dashed", color="#707070", fontcolor="#707070"]
7 -> 8 [id=16, label=<>, style="dashed", color="#707070", fontcolor="#707070"]
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
digraph {
compound=true
graph [fontname="Arial", rankdir=TB, ranksep=1.0, nodesep=1.0]
node [fontname="Arial", shape=box, margin="0.4,0.3"]
edge [fontname="Arial"]
label=<<br /><font point-size="34">F - Dynamic</font>>

subgraph cluster_6 {
margin=25
label=<<font point-size="24"><br />F</font><br /><font point-size="19">[Container]</font>>
labelloc=b
color="#444444"
fontcolor="#444444"
fillcolor="#444444"

subgraph "cluster_group_Group 5" {
margin=25
label=<<font point-size="24"><br />Group 5</font>>
labelloc=b
color="#cccccc"
fontcolor="#cccccc"
fillcolor="#ffffff"
style="dashed"

8 [id=8,shape=rect, label=<<font point-size="34">H</font><br /><font point-size="19">[Component]</font>>, style=filled, color="#9a9a9a", fillcolor="#dddddd", fontcolor="#000000"]
}

7 [id=7,shape=rect, label=<<font point-size="34">G</font><br /><font point-size="19">[Component]</font>>, style=filled, color="#9a9a9a", fillcolor="#dddddd", fontcolor="#000000"]
}

7 -> 8 [id=16, label=<<font point-size="24">1. </font>>, style="dashed", color="#707070", fontcolor="#707070"]
}
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@ public void test_GroupsExample() throws Exception {

MermaidDiagramExporter exporter = new MermaidDiagramExporter();
Collection<Diagram> diagrams = exporter.export(workspace);
assertEquals(3, diagrams.size());
assertEquals(4, diagrams.size());

Diagram diagram = diagrams.stream().filter(md -> md.getKey().equals("SystemLandscape")).findFirst().get();
String expected = readFile(new File("./src/test/java/com/structurizr/export/mermaid/groups-SystemLandscape.mmd"));
Expand All @@ -94,6 +94,10 @@ public void test_GroupsExample() throws Exception {
diagram = diagrams.stream().filter(md -> md.getKey().equals("Components")).findFirst().get();
expected = readFile(new File("./src/test/java/com/structurizr/export/mermaid/groups-Components.mmd"));
assertEquals(expected, diagram.getDefinition());

diagram = diagrams.stream().filter(md -> md.getKey().equals("Dynamic")).findFirst().get();
expected = readFile(new File("./src/test/java/com/structurizr/export/mermaid/groups-Dynamic.mmd"));
assertEquals(expected, diagram.getDefinition());
}

@Test
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,4 +23,5 @@ graph TB

3-. "<div></div><div style='font-size: 70%'></div>" .->7
3-. "<div></div><div style='font-size: 70%'></div>" .->8
7-. "<div></div><div style='font-size: 70%'></div>" .->8
end
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
sequenceDiagram

participant 7 as G<br />[Component]
participant 8 as H<br />[Component]

7->>8:
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,7 @@ public void test_GroupsExample() throws Exception {

C4PlantUMLExporter exporter = new C4PlantUMLExporter();
Collection<Diagram> diagrams = exporter.export(workspace);
assertEquals(3, diagrams.size());
assertEquals(4, diagrams.size());

Diagram diagram = diagrams.stream().filter(md -> md.getKey().equals("SystemLandscape")).findFirst().get();
String expected = readFile(new File("./src/test/java/com/structurizr/export/plantuml/c4plantuml/groups-SystemLandscape.puml"));
Expand All @@ -112,6 +112,10 @@ public void test_GroupsExample() throws Exception {
diagram = diagrams.stream().filter(md -> md.getKey().equals("Components")).findFirst().get();
expected = readFile(new File("./src/test/java/com/structurizr/export/plantuml/c4plantuml/groups-Components.puml"));
assertEquals(expected, diagram.getDefinition());

diagram = diagrams.stream().filter(md -> md.getKey().equals("Dynamic")).findFirst().get();
expected = readFile(new File("./src/test/java/com/structurizr/export/plantuml/c4plantuml/groups-Dynamic.puml"));
assertEquals(expected, diagram.getDefinition());
}

@Test
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,7 @@ public void test_GroupsExample() throws Exception {

StructurizrPlantUMLExporter exporter = new StructurizrPlantUMLExporter();
Collection<Diagram> diagrams = exporter.export(workspace);
assertEquals(3, diagrams.size());
assertEquals(4, diagrams.size());

Diagram diagram = diagrams.stream().filter(md -> md.getKey().equals("SystemLandscape")).findFirst().get();
String expected = readFile(new File("./src/test/java/com/structurizr/export/plantuml/structurizr/groups-SystemLandscape.puml"));
Expand All @@ -108,6 +108,28 @@ public void test_GroupsExample() throws Exception {
diagram = diagrams.stream().filter(md -> md.getKey().equals("Components")).findFirst().get();
expected = readFile(new File("./src/test/java/com/structurizr/export/plantuml/structurizr/groups-Components.puml"));
assertEquals(expected, diagram.getDefinition());

diagram = diagrams.stream().filter(md -> md.getKey().equals("Dynamic")).findFirst().get();
expected = readFile(new File("./src/test/java/com/structurizr/export/plantuml/structurizr/groups-Dynamic.puml"));
assertEquals(expected, diagram.getDefinition());
}

@Test
public void test_Sequence() throws Exception {
Workspace workspace = WorkspaceUtils.loadWorkspaceFromJson(new File("./src/test/resources/sequence.json"));
ThemeUtils.loadThemes(workspace);

StructurizrPlantUMLExporter exporter = new StructurizrPlantUMLExporter();
Collection<Diagram> diagrams = exporter.export(workspace);
assertEquals(2, diagrams.size());

Diagram diagram = diagrams.stream().filter(md -> md.getKey().equals("Sequence-Container")).findFirst().get();
String expected = readFile(new File("./src/test/java/com/structurizr/export/plantuml/structurizr/sequence-Container.puml"));
assertEquals(expected, diagram.getDefinition());

diagram = diagrams.stream().filter(md -> md.getKey().equals("Sequence-SoftwareSystem")).findFirst().get();
expected = readFile(new File("./src/test/java/com/structurizr/export/plantuml/structurizr/sequence-SoftwareSystem.puml"));
assertEquals(expected, diagram.getDefinition());
}

@Test
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ Container_Boundary("D.F_boundary", "F", $tags="") {

Rel(C, D.F.G, "", $techn="", $tags="", $link="")
Rel(C, D.F.H, "", $techn="", $tags="", $link="")
Rel(D.F.G, D.F.H, "", $techn="", $tags="", $link="")

SHOW_LEGEND(true)
@enduml
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
@startuml
set separator none
title F - Dynamic

!include <C4/C4_Sequence>

Component(D.F.G, "G", $techn="", $descr="", $tags="", $link="")
Component(D.F.H, "H", $techn="", $descr="", $tags="", $link="")

Rel(D.F.G, D.F.H, "", $techn="", $tags="", $link="")

SHOW_LEGEND(true)
@enduml
Loading