From 62c05c4b05b69979e1c8f094e999690d663fb127 Mon Sep 17 00:00:00 2001 From: Trung Mai Date: Wed, 19 Jun 2024 09:57:01 +0700 Subject: [PATCH] TE-612: Add filter for demo app --- .../analyzer/demo/ProcessAnalyzerBean.java | 30 +- .../AnalyzerDetail/AnalyzerDetail.xhtml | 22 +- .../resources/analyzer-detail.css | 16 +- .../AnalyzerSelection/AnalyzerSelection.xhtml | 16 +- .../resources/analyzer-selection.css | 11 + .../org.eclipse.core.resources.prefs | 2 + process-analyzer-product/README.md | 15 +- process-analyzer-product/product.json | 6 + .../test/FlowMixedSubProcessData.ivyClass | 2 + .../processes/FlowMixedSubProcess.p.json | 617 ++++++++++++++++++ .../analyzer/test/FlowMixedSubProcess.java | 37 ++ .../analyzer/AdvancedProcessAnalyzer.java | 4 +- 12 files changed, 763 insertions(+), 15 deletions(-) create mode 100644 process-analyzer-demo/src_hd/com/axonivy/utils/process/analyzer/demo/component/AnalyzerSelection/resources/analyzer-selection.css create mode 100644 process-analyzer-product/.settings/org.eclipse.core.resources.prefs create mode 100644 process-analyzer-test/dataclasses/com/axonivy/utils/estimator/test/FlowMixedSubProcessData.ivyClass create mode 100644 process-analyzer-test/processes/FlowMixedSubProcess.p.json create mode 100644 process-analyzer-test/src_test/com/axonivy/utils/process/analyzer/test/FlowMixedSubProcess.java diff --git a/process-analyzer-demo/src/com/axonivy/utils/process/analyzer/demo/ProcessAnalyzerBean.java b/process-analyzer-demo/src/com/axonivy/utils/process/analyzer/demo/ProcessAnalyzerBean.java index cf66159c..3bcac57b 100644 --- a/process-analyzer-demo/src/com/axonivy/utils/process/analyzer/demo/ProcessAnalyzerBean.java +++ b/process-analyzer-demo/src/com/axonivy/utils/process/analyzer/demo/ProcessAnalyzerBean.java @@ -11,9 +11,11 @@ import java.util.Map; import java.util.stream.Collectors; +import javax.annotation.PostConstruct; import javax.faces.event.AjaxBehaviorEvent; import org.primefaces.component.selectoneradio.SelectOneRadio; +import org.primefaces.model.FilterMeta; import com.axonivy.utils.process.analyzer.AdvancedProcessAnalyzer; import com.axonivy.utils.process.analyzer.demo.constant.FindType; @@ -23,6 +25,7 @@ import com.axonivy.utils.process.analyzer.internal.ProcessAnalyzer; import com.axonivy.utils.process.analyzer.model.DetectedAlternative; import com.axonivy.utils.process.analyzer.model.DetectedElement; +import com.axonivy.utils.process.analyzer.model.DetectedTask; import ch.ivyteam.ivy.environment.Ivy; import ch.ivyteam.ivy.process.model.BaseElement; @@ -45,7 +48,9 @@ public class ProcessAnalyzerBean { private List analyzers = new ArrayList<>(); private List processes = emptyList(); - + + private List filterBy; + private Analyzer selectedAnalyzer = null; AdvancedProcessAnalyzer processAnalyzer; @@ -73,7 +78,19 @@ public Analyzer getSelectedAnalyzer() { public void setSelectedAnalyzer(Analyzer selectedAnalyzer) { this.selectedAnalyzer = selectedAnalyzer; } + + public List getFilterBy() { + return filterBy; + } + + public void setFilterBy(List filterBy) { + this.filterBy = filterBy; + } + @PostConstruct + public void init() { + filterBy = new ArrayList<>(); + } public List getAllTaskModifier() { this.processAnalyzer = new ProcessAnalyzer(); return getElementOfProcess(this.selectedAnalyzer.getProcess()).stream() @@ -196,6 +213,17 @@ public String getShortPid(String pid) { return pid.substring(index + 1); } + public List getParentElementNames(){ + if(selectedAnalyzer != null) { + return selectedAnalyzer.getTasks().stream() + .filter(DetectedTask.class::isInstance) + .map(DetectedTask.class::cast) + .map(DetectedTask::getDisplayParentElementNames) + .distinct() + .toList(); + } + return emptyList(); + } private AdvancedProcessAnalyzer updateProcessAnalyzer(Analyzer analyzer) { Map flowOverrides = getProcessFlowOverride(analyzer); processAnalyzer.disableDescribeAlternativeElements(); diff --git a/process-analyzer-demo/src_hd/com/axonivy/utils/process/analyzer/demo/component/AnalyzerDetail/AnalyzerDetail.xhtml b/process-analyzer-demo/src_hd/com/axonivy/utils/process/analyzer/demo/component/AnalyzerDetail/AnalyzerDetail.xhtml index f639364c..adb80191 100644 --- a/process-analyzer-demo/src_hd/com/axonivy/utils/process/analyzer/demo/component/AnalyzerDetail/AnalyzerDetail.xhtml +++ b/process-analyzer-demo/src_hd/com/axonivy/utils/process/analyzer/demo/component/AnalyzerDetail/AnalyzerDetail.xhtml @@ -45,7 +45,8 @@ + filterBy="#{data.processAnalyzerBean.filterBy}" + styleClass="ui-datatable-sm ui-datatable-gridlines ui-datatable-header-filter"> @@ -56,11 +57,11 @@ title="#{task.pid}" /> - + - + @@ -69,7 +70,20 @@ value="#{data.processAnalyzerBean.getDisplayDuration(task.estimatedDuration)}" /> - + + + + + + + + + diff --git a/process-analyzer-demo/src_hd/com/axonivy/utils/process/analyzer/demo/component/AnalyzerDetail/resources/analyzer-detail.css b/process-analyzer-demo/src_hd/com/axonivy/utils/process/analyzer/demo/component/AnalyzerDetail/resources/analyzer-detail.css index 64ebfda8..f0770dc0 100644 --- a/process-analyzer-demo/src_hd/com/axonivy/utils/process/analyzer/demo/component/AnalyzerDetail/resources/analyzer-detail.css +++ b/process-analyzer-demo/src_hd/com/axonivy/utils/process/analyzer/demo/component/AnalyzerDetail/resources/analyzer-detail.css @@ -3,4 +3,18 @@ .ui-datatable-data .text-overflow { white-space: nowrap; text-overflow: ellipsis; -} \ No newline at end of file +} +.ui-datatable-header-filter .ui-selectonemenu { + width: 100%; + min-width: 100% !important; +} + +.ui-datatable-header-filter .ui-selectonemenu-label { + white-space: nowrap; + text-overflow: ellipsis; +} + +table thead tr { + vertical-align: text-top; +} + \ No newline at end of file diff --git a/process-analyzer-demo/src_hd/com/axonivy/utils/process/analyzer/demo/component/AnalyzerSelection/AnalyzerSelection.xhtml b/process-analyzer-demo/src_hd/com/axonivy/utils/process/analyzer/demo/component/AnalyzerSelection/AnalyzerSelection.xhtml index ece7a525..8c6bc561 100644 --- a/process-analyzer-demo/src_hd/com/axonivy/utils/process/analyzer/demo/component/AnalyzerSelection/AnalyzerSelection.xhtml +++ b/process-analyzer-demo/src_hd/com/axonivy/utils/process/analyzer/demo/component/AnalyzerSelection/AnalyzerSelection.xhtml @@ -13,15 +13,16 @@ - + + styleClass="customPanelGrid ui-grid-selection" contentStyleClass="ui-fluid"> + value="#{data.processAnalyzerBean.selectedAnalyzer.process}" + filter="true" filterMatchMode="contains"> + value="#{data.processAnalyzerBean.selectedAnalyzer.startElement}" + filter="true" filterMatchMode="contains"> + value="#{data.processAnalyzerBean.selectedAnalyzer.findType}" + filter="true" filterMatchMode="contains"> @@ -55,7 +58,8 @@ + value="#{data.processAnalyzerBean.selectedAnalyzer.useCase}" + filter="true" filterMatchMode="contains"> useCase) throws Exception + + /** + * This method can be used to calculate expected duration from a starting point + * using a named flow or default flow. For parallel segments of the process, it + * will still use the “critical path” (same logic like worst case duration). + * + * @param startElement - Element where we start traversing the process + * @param useCase - Use case that should be used to read duration values. + * Durations will be set to 0 in case not provided. + * @return + * @throws Exception + */ + public Duration calculateDurationOfPath(BaseElement startElement, Enum useCase, String flowName) throws Exception; ``` ### Example diff --git a/process-analyzer-product/product.json b/process-analyzer-product/product.json index 5f537e93..c9a078c0 100644 --- a/process-analyzer-product/product.json +++ b/process-analyzer-product/product.json @@ -10,6 +10,12 @@ "artifactId": "process-analyzer-demo", "version": "${version}", "type": "iar" + }, + { + "groupId": "com.axonivy.utils.process.analyzer", + "artifactId": "process-analyzer-test", + "version": "${version}", + "type": "iar" } ], "repositories": [ diff --git a/process-analyzer-test/dataclasses/com/axonivy/utils/estimator/test/FlowMixedSubProcessData.ivyClass b/process-analyzer-test/dataclasses/com/axonivy/utils/estimator/test/FlowMixedSubProcessData.ivyClass new file mode 100644 index 00000000..71e50664 --- /dev/null +++ b/process-analyzer-test/dataclasses/com/axonivy/utils/estimator/test/FlowMixedSubProcessData.ivyClass @@ -0,0 +1,2 @@ +FlowMixedSubProcessData #class +com.axonivy.utils.estimator.test #namespace diff --git a/process-analyzer-test/processes/FlowMixedSubProcess.p.json b/process-analyzer-test/processes/FlowMixedSubProcess.p.json new file mode 100644 index 00000000..3642601d --- /dev/null +++ b/process-analyzer-test/processes/FlowMixedSubProcess.p.json @@ -0,0 +1,617 @@ +{ + "$schema" : "https://json-schema.axonivy.com/process/11.2.2/process.json", + "id" : "1902A31FF5BCFF03", + "config" : { + "data" : "com.axonivy.utils.estimator.test.FlowMixedSubProcessData" + }, + "elements" : [ { + "id" : "f0", + "type" : "RequestStart", + "name" : "start", + "config" : { + "signature" : "start" + }, + "visual" : { + "at" : { "x" : 32, "y" : 128 } + }, + "connect" : [ + { "id" : "f2", "to" : "f14", "var" : "in1" } + ] + }, { + "id" : "f3", + "type" : "TaskSwitchGateway", + "name" : "split1", + "config" : { + "tasks" : [ { + "id" : "TaskA", + "responsible" : { + "activator" : "SYSTEM" + } + }, { + "id" : "TaskB", + "responsible" : { + "activator" : "SYSTEM" + } + } ] + }, + "visual" : { + "at" : { "x" : 288, "y" : 128 }, + "labelOffset" : { "x" : 16, "y" : -24 } + }, + "connect" : [ + { "id" : "f1", "to" : "f4", "condition" : "ivp==\"TaskA.ivp\"", "var" : "in1" }, + { "id" : "f7", "to" : "S30", "via" : [ { "x" : 288, "y" : 328 } ], "condition" : "ivp==\"TaskB.ivp\"" } + ] + }, { + "id" : "S10", + "type" : "EmbeddedProcess", + "name" : "SubA", + "elements" : [ { + "id" : "S10-g0", + "type" : "EmbeddedStart", + "name" : "from split2", + "visual" : { + "at" : { "x" : 104, "y" : 264 }, + "labelOffset" : { "x" : 11, "y" : 27 } + }, + "parentConnector" : "f5", + "connect" : [ + { "id" : "S10-f0", "to" : "S10-f1" } + ] + }, { + "id" : "S10-g1", + "type" : "EmbeddedEnd", + "name" : "to SubD", + "visual" : { + "at" : { "x" : 560, "y" : 264 }, + "labelOffset" : { "x" : 11, "y" : 35 } + }, + "parentConnector" : "f12" + }, { + "id" : "S10-f1", + "type" : "UserTask", + "name" : "SubA-TaskA", + "config" : { + "dialog" : "com.axonivy.utils.process.analyzer.test.Dummy:start()", + "task" : { + "name" : "SubA-TaskA", + "code" : [ + "import java.util.concurrent.TimeUnit;", + "import com.axonivy.utils.process.analyzer.APAConfig;", + "import com.axonivy.utils.process.analyzer.test.UseCase;", + "", + "APAConfig.setEstimate(5,TimeUnit.HOURS,UseCase.BIGPROJECT);" + ] + } + }, + "visual" : { + "at" : { "x" : 240, "y" : 264 } + }, + "connect" : [ + { "id" : "S10-f2", "to" : "S10-f6" } + ] + }, { + "id" : "S10-g2", + "type" : "EmbeddedEnd", + "name" : "to SubB", + "visual" : { + "at" : { "x" : 560, "y" : 360 }, + "labelOffset" : { "x" : 27, "y" : 35 } + }, + "parentConnector" : "f16" + }, { + "id" : "S10-f3", + "type" : "TaskSwitchGateway", + "config" : { + "tasks" : [ { + "id" : "TaskA", + "responsible" : { + "activator" : "SYSTEM" + } + }, { + "id" : "TaskB", + "responsible" : { + "activator" : "SYSTEM" + } + } ] + }, + "visual" : { + "at" : { "x" : 440, "y" : 264 } + }, + "connect" : [ + { "id" : "S10-f4", "to" : "S10-g1", "condition" : "ivp==\"TaskA.ivp\"" }, + { "id" : "S10-f5", "to" : "S10-f12", "condition" : "ivp==\"TaskB.ivp\"" } + ] + }, { + "id" : "S10-f6", + "type" : "Alternative", + "config" : { + "conditions" : { + "S10-f7" : "true" + } + }, + "visual" : { + "at" : { "x" : 368, "y" : 264 } + }, + "connect" : [ + { "id" : "S10-f7", "to" : "S10-f3", "var" : "in1" }, + { "id" : "S10-f9", "to" : "S10-f8" } + ] + }, { + "id" : "S10-f8", + "type" : "UserTask", + "name" : "SubA-TaskB", + "config" : { + "dialog" : "com.axonivy.utils.process.analyzer.test.Dummy:start()", + "task" : { + "name" : "SubA-TaskB", + "code" : [ + "import java.util.concurrent.TimeUnit;", + "import com.axonivy.utils.process.analyzer.APAConfig;", + "import com.axonivy.utils.process.analyzer.test.UseCase;", + "", + "APAConfig.setEstimate(6,TimeUnit.HOURS,UseCase.BIGPROJECT);" + ] + } + }, + "visual" : { + "at" : { "x" : 368, "y" : 168 } + }, + "connect" : [ + { "id" : "S10-f11", "to" : "S10-f10" } + ] + }, { + "id" : "S10-f10", + "type" : "TaskEnd", + "visual" : { + "at" : { "x" : 544, "y" : 168 } + } + }, { + "id" : "S10-f12", + "type" : "UserTask", + "name" : "SubA-TaskC", + "config" : { + "dialog" : "com.axonivy.utils.process.analyzer.test.Dummy:start()", + "task" : { + "name" : "SubA-TaskC", + "code" : [ + "import java.util.concurrent.TimeUnit;", + "import com.axonivy.utils.process.analyzer.APAConfig;", + "import com.axonivy.utils.process.analyzer.test.UseCase;", + "", + "APAConfig.setEstimate(5,TimeUnit.HOURS,UseCase.BIGPROJECT);" + ] + } + }, + "visual" : { + "at" : { "x" : 440, "y" : 360 } + }, + "connect" : [ + { "id" : "S10-f13", "to" : "S10-g2" } + ] + } ], + "visual" : { + "at" : { "x" : 536, "y" : 80 } + }, + "connect" : [ + { "id" : "f12", "to" : "S40", "via" : [ { "x" : 784, "y" : 80 } ] }, + { "id" : "f16", "to" : "S20" } + ] + }, { + "id" : "f4", + "type" : "TaskSwitchGateway", + "name" : "split2", + "config" : { + "tasks" : [ { + "id" : "TaskB", + "responsible" : { + "activator" : "SYSTEM" + } + }, { + "id" : "TaskA", + "responsible" : { + "activator" : "SYSTEM" + } + } ] + }, + "visual" : { + "at" : { "x" : 384, "y" : 128 }, + "labelOffset" : { "x" : -8, "y" : -8 } + }, + "connect" : [ + { "id" : "f6", "to" : "S20", "via" : [ { "x" : 384, "y" : 200 } ], "condition" : "ivp==\"TaskB.ivp\"" }, + { "id" : "f5", "to" : "S10", "via" : [ { "x" : 384, "y" : 80 } ], "condition" : "ivp==\"TaskA.ivp\"" } + ] + }, { + "id" : "S20", + "type" : "EmbeddedProcess", + "name" : "SubB", + "elements" : [ { + "id" : "S20-g0", + "type" : "EmbeddedStart", + "name" : "from SubB", + "visual" : { + "at" : { "x" : 192, "y" : 168 } + }, + "parentConnector" : "f6", + "connect" : [ + { "id" : "S20-f0", "to" : "S20-f7", "var" : "in1" } + ] + }, { + "id" : "S20-g1", + "type" : "EmbeddedEnd", + "name" : "to SubD", + "visual" : { + "at" : { "x" : 632, "y" : 72 }, + "labelOffset" : { "x" : 3, "y" : 43 } + }, + "parentConnector" : "f11" + }, { + "id" : "S20-f1", + "type" : "UserTask", + "name" : "SubB-TaskA", + "config" : { + "dialog" : "com.axonivy.utils.process.analyzer.test.Dummy:start()", + "task" : { + "name" : "SubB-TaskA", + "code" : [ + "import java.util.concurrent.TimeUnit;", + "import com.axonivy.utils.process.analyzer.APAConfig;", + "import com.axonivy.utils.process.analyzer.test.UseCase;", + "", + "APAConfig.setEstimate(5,TimeUnit.HOURS,UseCase.BIGPROJECT);" + ] + } + }, + "visual" : { + "at" : { "x" : 456, "y" : 120 } + }, + "connect" : [ + { "id" : "S20-f2", "to" : "S20-f3", "var" : "in1" } + ] + }, { + "id" : "S20-g2", + "type" : "EmbeddedEnd", + "name" : "to SubC", + "visual" : { + "at" : { "x" : 624, "y" : 152 }, + "labelOffset" : { "x" : 3, "y" : 27 } + }, + "parentConnector" : "f13" + }, { + "id" : "S20-f3", + "type" : "TaskSwitchGateway", + "config" : { + "tasks" : [ { + "id" : "TaskA", + "responsible" : { + "activator" : "SYSTEM" + } + }, { + "id" : "TaskB", + "responsible" : { + "activator" : "SYSTEM" + } + } ] + }, + "visual" : { + "at" : { "x" : 552, "y" : 120 } + }, + "connect" : [ + { "id" : "S20-f4", "to" : "S20-g1", "condition" : "ivp==\"TaskA.ivp\"" }, + { "id" : "S20-f5", "to" : "S20-g2", "condition" : "ivp==\"TaskB.ivp\"" } + ] + }, { + "id" : "S20-g3", + "type" : "EmbeddedStart", + "name" : "from SubA", + "visual" : { + "at" : { "x" : 208, "y" : 56 } + }, + "parentConnector" : "f16", + "connect" : [ + { "id" : "S20-f6", "to" : "S20-f7", "var" : "in2" } + ] + }, { + "id" : "S20-f7", + "type" : "TaskSwitchGateway", + "config" : { + "tasks" : [ { + "id" : "TaskA", + "responsible" : { + "activator" : "SYSTEM" + } + } ] + }, + "visual" : { + "at" : { "x" : 328, "y" : 120 } + }, + "connect" : [ + { "id" : "S20-f8", "to" : "S20-f1", "condition" : "ivp==\"TaskA.ivp\"" } + ] + } ], + "visual" : { + "at" : { "x" : 536, "y" : 200 } + }, + "connect" : [ + { "id" : "f11", "to" : "S40" }, + { "id" : "f13", "to" : "S30" } + ] + }, { + "id" : "S30", + "type" : "EmbeddedProcess", + "name" : "SubC", + "elements" : [ { + "id" : "S30-g0", + "type" : "EmbeddedStart", + "name" : "from split1", + "visual" : { + "at" : { "x" : 224, "y" : 64 } + }, + "parentConnector" : "f7", + "connect" : [ + { "id" : "S30-f0", "to" : "S30-f4", "var" : "in1" } + ] + }, { + "id" : "S30-g1", + "type" : "EmbeddedEnd", + "name" : "to SubD", + "visual" : { + "at" : { "x" : 672, "y" : 64 }, + "labelOffset" : { "x" : 27, "y" : 43 } + }, + "parentConnector" : "f10" + }, { + "id" : "S30-f1", + "type" : "UserTask", + "name" : "SubC-TaskA", + "config" : { + "dialog" : "com.axonivy.utils.process.analyzer.test.Dummy:start()", + "task" : { + "name" : "SubC-TaskA", + "code" : [ + "import java.util.concurrent.TimeUnit;", + "import com.axonivy.utils.process.analyzer.APAConfig;", + "import com.axonivy.utils.process.analyzer.test.UseCase;", + "", + "APAConfig.setEstimate(5,TimeUnit.HOURS,UseCase.BIGPROJECT);" + ] + } + }, + "visual" : { + "at" : { "x" : 448, "y" : 64 } + }, + "connect" : [ + { "id" : "S30-f2", "to" : "S30-g1" } + ] + }, { + "id" : "S30-g2", + "type" : "EmbeddedStart", + "name" : "from SubB", + "visual" : { + "at" : { "x" : 216, "y" : 136 } + }, + "parentConnector" : "f13", + "connect" : [ + { "id" : "S30-f3", "to" : "S30-f4", "var" : "in2" } + ] + }, { + "id" : "S30-f4", + "type" : "TaskSwitchGateway", + "config" : { + "tasks" : [ { + "id" : "TaskA", + "responsible" : { + "activator" : "SYSTEM" + } + } ] + }, + "visual" : { + "at" : { "x" : 320, "y" : 64 } + }, + "connect" : [ + { "id" : "S30-f5", "to" : "S30-f1", "condition" : "ivp==\"TaskA.ivp\"" } + ] + } ], + "visual" : { + "at" : { "x" : 688, "y" : 328 } + }, + "connect" : [ + { "id" : "f10", "to" : "S40" } + ] + }, { + "id" : "S40", + "type" : "EmbeddedProcess", + "name" : "SubD", + "elements" : [ { + "id" : "S40-g0", + "type" : "EmbeddedEnd", + "visual" : { + "at" : { "x" : 672, "y" : 152 } + }, + "parentConnector" : "f9" + }, { + "id" : "S40-f1", + "type" : "UserTask", + "name" : "SubD-TaskA", + "config" : { + "dialog" : "com.axonivy.utils.process.analyzer.test.Dummy:start()", + "task" : { + "name" : "SubD-TaskA", + "code" : [ + "import java.util.concurrent.TimeUnit;", + "import com.axonivy.utils.process.analyzer.APAConfig;", + "import com.axonivy.utils.process.analyzer.test.UseCase;", + "", + "APAConfig.setEstimate(5,TimeUnit.HOURS,UseCase.BIGPROJECT);" + ] + } + }, + "visual" : { + "at" : { "x" : 552, "y" : 152 } + }, + "connect" : [ + { "id" : "S40-f2", "to" : "S40-g0" } + ] + }, { + "id" : "S40-f3", + "type" : "TaskSwitchGateway", + "config" : { + "tasks" : [ { + "id" : "TaskA", + "responsible" : { + "activator" : "SYSTEM" + } + } ] + }, + "visual" : { + "at" : { "x" : 432, "y" : 144 } + }, + "connect" : [ + { "id" : "S40-f4", "to" : "S40-f1", "condition" : "ivp==\"TaskA.ivp\"" } + ] + }, { + "id" : "S40-g1", + "type" : "EmbeddedStart", + "name" : "from SubC", + "visual" : { + "at" : { "x" : 168, "y" : 224 }, + "labelOffset" : { "x" : 19, "y" : 35 } + }, + "parentConnector" : "f10", + "connect" : [ + { "id" : "S40-f0", "to" : "S40-f9", "var" : "in1" } + ] + }, { + "id" : "S40-g2", + "type" : "EmbeddedStart", + "name" : "from subB", + "visual" : { + "at" : { "x" : 168, "y" : 152 } + }, + "parentConnector" : "f11", + "connect" : [ + { "id" : "S40-f5", "to" : "S40-f11", "var" : "in2" } + ] + }, { + "id" : "S40-g3", + "type" : "EmbeddedStart", + "name" : "from SubA", + "visual" : { + "at" : { "x" : 168, "y" : 80 }, + "labelOffset" : { "x" : 11, "y" : 27 } + }, + "parentConnector" : "f12", + "connect" : [ + { "id" : "S40-f6", "to" : "S40-f7", "var" : "in3" } + ] + }, { + "id" : "S40-f7", + "type" : "UserTask", + "name" : "SubD-TaskB", + "config" : { + "dialog" : "com.axonivy.utils.process.analyzer.test.Dummy:start()", + "task" : { + "name" : "SubD-TaskB", + "code" : [ + "import java.util.concurrent.TimeUnit;", + "import com.axonivy.utils.process.analyzer.APAConfig;", + "import com.axonivy.utils.process.analyzer.test.UseCase;", + "", + "APAConfig.setEstimate(3,TimeUnit.HOURS,UseCase.BIGPROJECT);" + ] + } + }, + "visual" : { + "at" : { "x" : 296, "y" : 80 } + }, + "connect" : [ + { "id" : "S40-f8", "to" : "S40-f3", "var" : "in3" } + ] + }, { + "id" : "S40-f9", + "type" : "UserTask", + "name" : "SubD-TaskD", + "config" : { + "dialog" : "com.axonivy.utils.process.analyzer.test.Dummy:start()", + "call" : { + "map" : { }, + "code" : [ + "import java.util.concurrent.TimeUnit;", + "import com.axonivy.utils.process.analyzer.APAConfig;", + "import com.axonivy.utils.process.analyzer.test.UseCase;", + "", + "APAConfig.setEstimate(5,TimeUnit.HOURS,UseCase.BIGPROJECT);" + ] + }, + "task" : { + "name" : "SubD-TaskB" + } + }, + "visual" : { + "at" : { "x" : 296, "y" : 224 } + }, + "connect" : [ + { "id" : "S40-f10", "to" : "S40-f3", "var" : "in1" } + ] + }, { + "id" : "S40-f11", + "type" : "UserTask", + "name" : "SubD-TaskC", + "config" : { + "dialog" : "com.axonivy.utils.process.analyzer.test.Dummy:start()", + "task" : { + "name" : "SubD-TaskC", + "code" : [ + "import java.util.concurrent.TimeUnit;", + "import com.axonivy.utils.process.analyzer.APAConfig;", + "import com.axonivy.utils.process.analyzer.test.UseCase;", + "", + "APAConfig.setEstimate(4,TimeUnit.HOURS,UseCase.BIGPROJECT);" + ] + } + }, + "visual" : { + "at" : { "x" : 296, "y" : 152 } + }, + "connect" : [ + { "id" : "S40-f12", "to" : "S40-f3", "var" : "in2" } + ] + } ], + "visual" : { + "at" : { "x" : 784, "y" : 200 } + }, + "connect" : [ + { "id" : "f9", "to" : "f8" } + ] + }, { + "id" : "f8", + "type" : "TaskEnd", + "visual" : { + "at" : { "x" : 920, "y" : 200 } + } + }, { + "id" : "f14", + "type" : "UserTask", + "name" : "TaskA", + "config" : { + "dialog" : "com.axonivy.utils.process.analyzer.test.Dummy:start()", + "task" : { + "name" : "TaskA", + "code" : [ + "import java.util.concurrent.TimeUnit;", + "import com.axonivy.utils.process.analyzer.APAConfig;", + "import com.axonivy.utils.process.analyzer.test.UseCase;", + "", + "APAConfig.setEstimate(5,TimeUnit.HOURS,UseCase.BIGPROJECT);" + ] + } + }, + "visual" : { + "at" : { "x" : 160, "y" : 128 } + }, + "connect" : [ + { "id" : "f15", "to" : "f3", "var" : "in1" } + ] + } ] +} \ No newline at end of file diff --git a/process-analyzer-test/src_test/com/axonivy/utils/process/analyzer/test/FlowMixedSubProcess.java b/process-analyzer-test/src_test/com/axonivy/utils/process/analyzer/test/FlowMixedSubProcess.java new file mode 100644 index 00000000..8844c0f1 --- /dev/null +++ b/process-analyzer-test/src_test/com/axonivy/utils/process/analyzer/test/FlowMixedSubProcess.java @@ -0,0 +1,37 @@ +package com.axonivy.utils.process.analyzer.test; + +import static org.junit.jupiter.api.Assertions.assertArrayEquals; + +import org.assertj.core.util.Arrays; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import com.axonivy.utils.process.analyzer.internal.ProcessAnalyzer; + +import ch.ivyteam.ivy.environment.IvyTest; + +@IvyTest +public class FlowMixedSubProcess extends FlowExampleTest { + private static final String PROCESS_NAME = "FlowMixedSubProcess"; + + @BeforeAll + public static void setup() { + setup(PROCESS_NAME); + } + + @BeforeEach + public void setupForEach() { + processAnalyzer = new ProcessAnalyzer(); + } + + @Test + void shouldFindAllTasks() throws Exception { + var start = ProcessGraphHelper.findByElementName(process, "start"); + var detectedTasks = processAnalyzer.findAllTasks(start, UseCase.BIGPROJECT); + + var expected = Arrays.array("TaskA", "SubA-TaskA", "SubA-TaskC", "SubA-TaskB", "SubD-TaskB", "SubB-TaskA", "SubD-TaskC", "SubC-TaskA", "SubD-TaskB", "SubD-TaskA"); + var taskNames = getTaskNames(detectedTasks); + assertArrayEquals(expected, taskNames); + } +} diff --git a/process-analyzer/src/com/axonivy/utils/process/analyzer/AdvancedProcessAnalyzer.java b/process-analyzer/src/com/axonivy/utils/process/analyzer/AdvancedProcessAnalyzer.java index 3072c559..7837b24d 100644 --- a/process-analyzer/src/com/axonivy/utils/process/analyzer/AdvancedProcessAnalyzer.java +++ b/process-analyzer/src/com/axonivy/utils/process/analyzer/AdvancedProcessAnalyzer.java @@ -175,7 +175,7 @@ public List findTasksOnPath(List startAtElements, /** * This method can be used to calculate expected duration from a starting point * using a named flow or default flow. For parallel segments of the process, it - * will still use the “critical path” (same logic like worst case duration). * + * will still use the “critical path” (same logic like worst case duration). * * @param startElement - Element where we start traversing the process * @param useCase - Use case that should be used to read duration values. @@ -189,7 +189,7 @@ public Duration calculateDurationOfPath(BaseElement startElement, Enum useCas /** * This method can be used to calculate expected duration from a starting point * using a named flow or default flow. For parallel segments of the process, it - * will still use the “critical path” (same logic like worst case duration). + * will still use the “critical pathâ€� (same logic like worst case duration). * * @param useCase - Use case that should be used to read duration values. * Durations will be set to 0 in case not provided.