Skip to content
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
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/)
- Cleaned up AcknowledgementLetterFromSource example
- Fixed handling of styles containing spaces sometimes causing deployment errors
- Truncating content preview in area mapping for better readability
- Potential condition variable name collision solved by better naming and positioning under the condition flow/rowset

## [17.0.25] - 2026-06-15

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -207,8 +207,11 @@ abstract class InspireDocumentObjectBuilder(
protected open fun wrapSuccessFlowInConditionFlow(
layout: Layout, variableStructure: VariableStructure, rule: DisplayRule, successFlow: Flow
): Flow {
return layout.addFlow().setType(Flow.Type.SELECT_BY_CONDITION).addLineForSelectByCondition(
layout.data.addVariable().setKind(VariableKind.CALCULATED).setDataType(DataType.BOOL)
val conditionFlow = layout.addFlow().setType(Flow.Type.SELECT_BY_CONDITION)
return conditionFlow.addLineForSelectByCondition(
conditionFlow.addVariable()
.setName(conditionVariableName(rule))
.setKind(VariableKind.CALCULATED).setDataType(DataType.BOOL)
.setScript(rule.toScript(
layout,
variableStructure,
Expand All @@ -229,22 +232,27 @@ abstract class InspireDocumentObjectBuilder(
innerRowSet: GeneralRowSet? = null,
): GeneralRowSet {
val successRow = innerRowSet ?: layout.addRowSet().setType(RowSet.Type.SINGLE_ROW)
return layout.addRowSet().setType(RowSet.Type.SELECT_BY_CONDITION)
.addLineForSelectByCondition(
layout.data.addVariable().setKind(VariableKind.CALCULATED).setDataType(DataType.BOOL)
.setScript(rule.toScript(
layout,
variableStructure,
variableRepository::findOrFail,
displayRuleRepository::findOrFail,
resourcePathProvider::getDisplayRulePath,
output,
projectConfig.interactiveTenant
)),
successRow
)
val conditionRowSet = layout.addRowSet().setType(RowSet.Type.SELECT_BY_CONDITION)
return conditionRowSet.addLineForSelectByCondition(
conditionRowSet.addVariable()
.setName(conditionVariableName(rule))
.setKind(VariableKind.CALCULATED).setDataType(DataType.BOOL)
.setScript(rule.toScript(
layout,
variableStructure,
variableRepository::findOrFail,
displayRuleRepository::findOrFail,
resourcePathProvider::getDisplayRulePath,
output,
projectConfig.interactiveTenant
)),
successRow
)
}

private fun conditionVariableName(rule: DisplayRule): String =
"cond_${rule.nameOrId()}"

protected fun wrapRowSetInConditionIfNeeded(
layout: Layout,
variableStructure: VariableStructure,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -411,6 +411,10 @@ class InteractiveDocumentObjectBuilderTest {
val successFlowRef = condition[""].stringValue()
val conditionVarRef = condition["VarId"].stringValue()

val conditionVarForwardRef = result["Variable"].first { it["Id"].stringValue() == conditionVarRef }
conditionVarForwardRef["ParentId"].stringValue().shouldBeEqualTo(conditionFlowRef)
conditionVarForwardRef["Name"].stringValue().shouldBeEqualTo("cond_R_1")

val conditionVar = result["Variable"].last { it["Id"].stringValue() == conditionVarRef }
conditionVar["VarType"].stringValue().shouldBeEqualTo("Bool")
conditionVar["Type"].stringValue().shouldBeEqualTo("Calculated")
Expand Down Expand Up @@ -574,10 +578,15 @@ class InteractiveDocumentObjectBuilderTest {

// then
val conditionalRow = result["RowSet"].last { it["RowSetType"]?.stringValue() == "Condition" }
val conditionalRowId = conditionalRow["Id"].stringValue()
val rowCondition = conditionalRow["RowSetCondition"][0]
val subRowRef = rowCondition["SubRowId"].stringValue()
val conditionVarRef = rowCondition["VariableId"].stringValue()

val conditionVarForwardRef = result["Variable"].first { it["Id"].stringValue() == conditionVarRef }
conditionVarForwardRef["ParentId"].stringValue().shouldBeEqualTo(conditionalRowId)
conditionVarForwardRef["Name"].stringValue().shouldBeEqualTo("cond_R_1")

val conditionVar = result["Variable"].last { it["Id"].stringValue() == conditionVarRef }
conditionVar["Type"].stringValue().shouldBeEqualTo("Calculated")
conditionVar["VarType"].stringValue().shouldBeEqualTo("Bool")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ public interface Flow extends Node<Flow> {

Paragraph addParagraph();

Variable addVariable();

boolean isSectionFlow();

Flow setSectionFlow(boolean sectionFlow);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@

public interface GeneralRowSet extends RowSet {

Variable addVariable();

GeneralRowSet setType(RowSet.Type rowSetType);

GeneralRowSet addCell(Cell cell);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package com.quadient.wfdxml.internal;

import java.util.List;

/**
* Marks a layout node that owns a private list of child nodes (e.g. condition variables)
* which are logically scoped to that node rather than to the global Data root.
* <p>
* Implementors supply the list via {@link #getLocalNodes()}; the
* {@code ForwardReferencesExporter} discovers and registers these nodes with a
* {@code ParentId} pointing to the owning node, matching the structure that
* Inspire Designer produces interactively.
*/
public interface HasLocalNodes {
List<NodeImpl> getLocalNodes();
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,17 @@

import com.quadient.wfdxml.api.layoutnodes.Flow;
import com.quadient.wfdxml.api.layoutnodes.data.Variable;
import com.quadient.wfdxml.internal.HasLocalNodes;
import com.quadient.wfdxml.internal.NodeImpl;
import com.quadient.wfdxml.internal.layoutnodes.data.LAVariableIface.VariableType;
import com.quadient.wfdxml.internal.layoutnodes.data.VariableImpl;
import com.quadient.wfdxml.internal.layoutnodes.data.WorkFlowTreeEnums.NodeType;
import com.quadient.wfdxml.internal.layoutnodes.flow.ParagraphImpl;
import com.quadient.wfdxml.internal.layoutnodes.support.FlowContent;
import com.quadient.wfdxml.internal.xml.export.XmlExporter;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

import static com.quadient.wfdxml.internal.layoutnodes.FlowImpl.Type.CONDITION;
Expand All @@ -28,8 +33,9 @@
import static com.quadient.wfdxml.internal.layoutnodes.FlowImpl.Type.TEXT;
import static com.quadient.wfdxml.internal.layoutnodes.FlowImpl.Type.VARIABLE_FORMATTED;

public class FlowImpl extends NodeImpl<Flow> implements Flow {
public class FlowImpl extends NodeImpl<Flow> implements Flow, HasLocalNodes {
private final List<FlowCondition> flowConditions = new ArrayList<>();
private final List<NodeImpl> localNodes = new ArrayList<>();
private Type type = SIMPLE;
private Variable variable;
private boolean sectionFlow = false;
Expand Down Expand Up @@ -292,6 +298,18 @@ public FlowImpl setVariable(Variable variable) {
return this;
}

@Override
public VariableImpl addVariable() {
VariableImpl var = new VariableImpl().setType(VariableType.CONSTANT).setNodeType(NodeType.STRING);
localNodes.add(var);
return var;
}

@Override
public List<NodeImpl> getLocalNodes() {
return Collections.unmodifiableList(localNodes);
}

enum Type {
SIMPLE,
INTEGER,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,15 @@
import com.quadient.wfdxml.api.layoutnodes.tables.GeneralRowSet;
import com.quadient.wfdxml.api.layoutnodes.tables.HeaderFooterRowSet;
import com.quadient.wfdxml.api.layoutnodes.tables.RowSet;
import com.quadient.wfdxml.internal.HasLocalNodes;
import com.quadient.wfdxml.internal.NodeImpl;
import com.quadient.wfdxml.internal.layoutnodes.data.LAVariableIface.VariableType;
import com.quadient.wfdxml.internal.layoutnodes.data.VariableImpl;
import com.quadient.wfdxml.internal.layoutnodes.data.WorkFlowTreeEnums.NodeType;
import com.quadient.wfdxml.internal.xml.export.XmlExporter;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

import static com.quadient.wfdxml.internal.layoutnodes.tables.RowSetImpl.Type.HEADER_FOOTER;
Expand All @@ -22,8 +27,9 @@
import static com.quadient.wfdxml.internal.layoutnodes.tables.RowSetImpl.Type.SWITCH_INT;
import static com.quadient.wfdxml.internal.layoutnodes.tables.RowSetImpl.Type.SWITCH_RANGE;

public class RowSetImpl extends NodeImpl<RowSet> implements GeneralRowSet, HeaderFooterRowSet {
public class RowSetImpl extends NodeImpl<RowSet> implements GeneralRowSet, HeaderFooterRowSet, HasLocalNodes {
private final List<Node> subRows = new ArrayList<>();
private final List<NodeImpl> localNodes = new ArrayList<>();
private final List<RowSetCondition> rowSetConditions = new ArrayList<>();
private Variable variable;
private Type rowSetType = ROW;
Expand Down Expand Up @@ -162,6 +168,18 @@ public Variable getVariable() {
return variable;
}

@Override
public VariableImpl addVariable() {
VariableImpl var = new VariableImpl().setType(VariableType.CONSTANT).setNodeType(NodeType.STRING);
localNodes.add(var);
return var;
}

@Override
public List<NodeImpl> getLocalNodes() {
return Collections.unmodifiableList(localNodes);
}

@Override
public RowSetImpl setVariable(Variable variable) {
this.variable = variable;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import com.quadient.wfdxml.api.layoutnodes.data.Variable;
import com.quadient.wfdxml.internal.DefaultNodeType;
import com.quadient.wfdxml.internal.HasLocalNodes;
import com.quadient.wfdxml.internal.NodeImpl;
import com.quadient.wfdxml.internal.Tree;
import com.quadient.wfdxml.internal.xml.export.XmlExporter;
Expand Down Expand Up @@ -51,10 +52,15 @@ private void exportTree(Tree tree, Boolean useExistingVariables) {
if (child instanceof Tree) {
exportTree((Tree) child, useExistingVariables);
}
if (child instanceof HasLocalNodes holder && !holder.getLocalNodes().isEmpty()) {
for (NodeImpl localNode : holder.getLocalNodes()) {
writeForwardReferenceToExporter(localNode, child, useExistingVariables);
}
}
}
}

private void writeForwardReferenceToExporter(NodeImpl node, Tree parent, Boolean useExistingVariables) {
private void writeForwardReferenceToExporter(NodeImpl node, NodeImpl parent, Boolean useExistingVariables) {
exporter.beginElement(node.getXmlElementName()).addElementWithIface("Id", node).addElementWithStringData("Name", node.getName()).addElementWithStringData("Comment", node.getComment());

if (node instanceof Variable variable && variable.getExistingParentId() != null) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
import com.quadient.wfdxml.api.module.Layout;
import com.quadient.wfdxml.internal.DefaultNodeType;
import com.quadient.wfdxml.internal.Group;
import com.quadient.wfdxml.internal.HasLocalNodes;
import com.quadient.wfdxml.internal.NodeImpl;
import com.quadient.wfdxml.internal.Tree;
import com.quadient.wfdxml.internal.layoutnodes.*;
Expand Down Expand Up @@ -374,7 +375,14 @@ private void exportTree(Tree tree, XmlExporter exporter) {
if (child instanceof Tree) {
exportTree((Tree) child, exporter);
}

if (child instanceof HasLocalNodes holder && !holder.getLocalNodes().isEmpty()) {
for (NodeImpl localNode : holder.getLocalNodes()) {
exporter.beginElement(localNode.getXmlElementName());
exporter.addElementWithIface("Id", localNode);
localNode.export(exporter);
exporter.endElement();
}
}
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -312,4 +312,16 @@ class FlowImplTest extends Specification {
<SectionFlow>True</SectionFlow>
""")
}

def "addVariable adds variable to localNodes"() {
given:
FlowImpl flow = new FlowImpl().setType(SELECT_BY_CONDITION)

when:
def variable = flow.addVariable().setName("cond_MyRule")

then:
assert flow.localNodes.size() == 1
assert flow.localNodes[0].is(variable)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -336,4 +336,16 @@ class RowSetImplTest extends Specification {
<TreatDefaultAsError>True</TreatDefaultAsError>
""")
}

def "addVariable adds variable to localNodes"() {
given:
RowSetImpl rowSet = new RowSetImpl().setType(SELECT_BY_CONDITION)

when:
def variable = rowSet.addVariable().setName("cond_MyRule")

then:
assert rowSet.localNodes.size() == 1
assert rowSet.localNodes[0].is(variable)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import com.quadient.wfdxml.api.layoutnodes.TextStyle
import com.quadient.wfdxml.api.layoutnodes.data.DataType
import com.quadient.wfdxml.api.layoutnodes.data.VariableKind
import com.quadient.wfdxml.api.layoutnodes.tables.Cell
import com.quadient.wfdxml.api.layoutnodes.tables.GeneralRowSet
import com.quadient.wfdxml.api.layoutnodes.tables.RowSet
import com.quadient.wfdxml.api.layoutnodes.tables.Table
import com.quadient.wfdxml.api.module.Layout
Expand Down Expand Up @@ -208,4 +209,42 @@ class LayoutImplTest extends Specification {
then:
assert result.contains("<ParentId>Def.FlowGroup</ParentId><CustomProperty>{&quot;ValueWrapperVariable&quot;:true,&quot;Version&quot;:2,&quot;DisplayName&quot;:&quot;Flow with multiple properties&quot;}</CustomProperty>")
}

def "local variable of a condition flow is exported with flow as parentId"() {
given:
Layout layout = new LayoutImpl()
def condFlow = layout.addFlow()
.setType(Flow.Type.SELECT_BY_CONDITION)
.setName("CondFlow")
.setId("CondFlowId")
condFlow.addVariable().setName("cond_MyRule").setKind(VariableKind.CALCULATED).setDataType(DataType.BOOL)

when:
layout.exportLayoutDelta(exporter)
String result = exporter.buildString()

then:
assert result.contains("<Name>cond_MyRule</Name>")
assert result.contains("<Type>Calculated</Type>")
assert result.contains("<ParentId>CondFlowId</ParentId>")
}

def "local variable of a condition rowset is exported with rowset as parentId"() {
given:
Layout layout = new LayoutImpl()
def condRowSet = layout.addRowSet()
.setType(RowSet.Type.SELECT_BY_CONDITION)
.setName("CondRowSet")
.setId("CondRowSetId") as GeneralRowSet
condRowSet.addVariable().setName("cond_MyRule").setKind(VariableKind.CALCULATED).setDataType(DataType.BOOL)

when:
layout.exportLayoutDelta(exporter)
String result = exporter.buildString()

then:
assert result.contains("<Name>cond_MyRule</Name>")
assert result.contains("<Type>Calculated</Type>")
assert result.contains("<ParentId>CondRowSetId</ParentId>")
}
}
Loading