Skip to content

allow to use custom workflow template for generatig diagrams #174

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

Merged
merged 1 commit into from
Jan 11, 2022
Merged
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
16 changes: 16 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -267,6 +267,22 @@ String diagramSVG = workflowDiagram.getSvgDiagram();
`diagramSVG` includes the diagram SVG source which you can then decide to save to a file,
print, or process further.

In case default visualization of the workflow is not sufficient you can provide custom workflow template to be
used while generating the SVG file. Easiest is to start off from the default template and customize it to your needs.

Custom template must be on the classpath in `templates/plantuml` directory and must use `.txt` extension. Next
template is set on `WorkflowDiagram` instance as shown below.

``` java
Workflow workflow = Workflow.fromSource(source);

WorkflowDiagram workflowDiagram = new WorkflowDiagramImpl();
workflowDiagram.setWorkflow(workflow);
workflowDiagram.setTemplate("custom-template");

String diagramSVG = workflowDiagram.getSvgDiagram();
```

By default the diagram legend is now shown. If you want to enable it you can do:

``` java
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@ public interface WorkflowDiagram {

WorkflowDiagram setSource(String source);

WorkflowDiagram setTemplate(String template);

String getSvgDiagram() throws Exception;

WorkflowDiagram showLegend(boolean showLegend);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,9 +26,14 @@

public class WorkflowDiagramImpl implements WorkflowDiagram {

public static final String DEFAULT_TEMPLATE = "workflow-template";

@SuppressWarnings("unused")
private String source;

@SuppressWarnings("unused")
private String template = DEFAULT_TEMPLATE;

private Workflow workflow;
private boolean showLegend = false;

Expand All @@ -46,12 +51,18 @@ public WorkflowDiagram setSource(String source) {
return this;
}

@Override
public WorkflowDiagram setTemplate(String template) {
this.template = template;
return this;
}

@Override
public String getSvgDiagram() throws Exception {
if (workflow == null) {
throw new IllegalAccessException("Unable to get diagram - no workflow set.");
}
String diagramSource = WorkflowToPlantuml.convert(workflow, showLegend);
String diagramSource = WorkflowToPlantuml.convert(template, workflow, showLegend);
SourceStringReader reader = new SourceStringReader(diagramSource);
final ByteArrayOutputStream os = new ByteArrayOutputStream();
reader.generateImage(os, new FileFormatOption(FileFormat.SVG));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,11 +22,12 @@
import org.thymeleaf.context.Context;

public class WorkflowToPlantuml {
public static String convert(Workflow workflow, boolean showLegend) {

public static String convert(String template, Workflow workflow, boolean showLegend) {
TemplateEngine plantUmlTemplateEngine = ThymeleafConfig.templateEngine;
Context context = new Context();
context.setVariable("diagram", new WorkflowDiagramModel(workflow, showLegend));

return plantUmlTemplateEngine.process("workflow-template", context);
return plantUmlTemplateEngine.process(template, context);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
/*
* Copyright 2020-Present The Serverless Workflow Specification Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package io.serverlessworkflow.diagram.test;

import static org.junit.jupiter.api.Assertions.assertNotNull;

import io.serverlessworkflow.api.Workflow;
import io.serverlessworkflow.api.interfaces.WorkflowDiagram;
import io.serverlessworkflow.diagram.WorkflowDiagramImpl;
import io.serverlessworkflow.diagram.test.utils.DiagramTestUtils;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.ValueSource;

public class CustomTemplateWorkflowDiagramTest {

@ParameterizedTest
@ValueSource(strings = {"/examples/applicantrequest.json", "/examples/applicantrequest.yml"})
public void testSpecExamplesParsing(String workflowLocation) throws Exception {

Workflow workflow = Workflow.fromSource(DiagramTestUtils.readWorkflowFile(workflowLocation));

assertNotNull(workflow);
assertNotNull(workflow.getId());
assertNotNull(workflow.getName());
assertNotNull(workflow.getStates());

WorkflowDiagram workflowDiagram =
new WorkflowDiagramImpl().setWorkflow(workflow).setTemplate("custom-template");

String diagramSVG = workflowDiagram.getSvgDiagram();

Assertions.assertNotNull(diagramSVG);
// custom template uses #0000FF as start node color
Assertions.assertTrue(diagramSVG.contains("#0000FF"));
}
}
46 changes: 46 additions & 0 deletions diagram/src/test/resources/templates/plantuml/custom-template.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
@startuml
skinparam backgroundColor White
skinparam legendBackgroundColor White
skinparam legendBorderColor White
skinparam state {
StartColor #0000FF
EndColor Orange
BackgroundColor GhostWhite
BackgroundColor<< workflow >> White
BorderColor Black
ArrowColor Black

BorderColor<< event >> #7fe5f0
BorderColor<< operation >> #bada55
BorderColor<< switch >> #92a0f2
BorderColor<< sleep >> #b83b5e
BorderColor<< parallel >> #6a2c70
BorderColor<< inject >> #1e5f74
BorderColor<< foreach >> #931a25
BorderColor<< callback >> #ffcb8e
}
state "[(${diagram.title})]" as workflow << workflow >> {

[# th:each="stateDef : ${diagram.modelStateDefs}" ]
[(${stateDef.toString()})]
[/]

[# th:each="state : ${diagram.modelStates}" ]
[(${state.toString()})]
[/]

[# th:each="connection : ${diagram.modelConnections}" ]
[(${connection.toString()})]
[/]

}

[# th:if="${diagram.showLegend}" ]
legend center
State Types and Border Colors:
| Event | Operation | Switch | Sleep | Parallel | Inject | ForEach | CallBack |
|<#7fe5f0>|<#bada55>|<#92a0f2>|<#b83b5e>|<#6a2c70>|<#1e5f74>|<#931a25>|<#ffcb8e>|
endlegend
[/]

@enduml