diff --git a/CHANGELOG.md b/CHANGELOG.md
index ef40e60..e5e2820 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -9,14 +9,19 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/)
### Added
- Added barcode and QR code support
+- Cell overflow options
### Changed
- Shape (line) in Migration Model Example moved to header part of the document to avoid collision with new and dynamic content
+- **Breaking** Pages in Interactive output no longer create standalone template .jld file, but are still taken into
+ account when distributing content to Interactive flows. Templates also work directly with areas in its content.
### Fixed
- First match snippet in Designer output rendered as an inline first match flow to better fit its inline nature
+- Wrapping cell content to block in Interactive output for specific cases
+- Image dimensions in Interactive can be editable even without specified height or width
## [17.0.21] - 2026-05-07
diff --git a/migration-examples/src/main/groovy/com/quadient/migration/example/common/mapping/AreasExport.groovy b/migration-examples/src/main/groovy/com/quadient/migration/example/common/mapping/AreasExport.groovy
index ccbca38..a5faf85 100644
--- a/migration-examples/src/main/groovy/com/quadient/migration/example/common/mapping/AreasExport.groovy
+++ b/migration-examples/src/main/groovy/com/quadient/migration/example/common/mapping/AreasExport.groovy
@@ -38,7 +38,7 @@ static void run(Migration migration, Path path) {
areasFile.withWriter { writer ->
def headers = [
- Mapping.displayHeader("templateId", true),
+ Mapping.displayHeader("templateId", false),
Mapping.displayHeader("templateName", true),
Mapping.displayHeader("pageId", false),
Mapping.displayHeader("pageName", true),
@@ -63,6 +63,11 @@ static void run(Migration migration, Path path) {
writer.writeLine(buildArea(migration, idx, area, page, template))
}
}
+
+ def directAreas = template.content.findAll { it instanceof Area } as List
+ directAreas.eachWithIndex { area, idx ->
+ writer.writeLine(buildArea(migration, idx, area, null, template))
+ }
}
if (usedPageIds.size() != pageIds.size()) {
@@ -83,8 +88,8 @@ static String buildArea(Migration migration, Number idx, Area area, DocumentObje
def builder = new StringBuilder()
builder.append(Csv.serialize(template?.id) + ",")
builder.append(Csv.serialize(template?.name) + ",")
- builder.append(Csv.serialize(page.id) + ",")
- builder.append(Csv.serialize(page.name) + ",")
+ builder.append(Csv.serialize(page?.id) + ",")
+ builder.append(Csv.serialize(page?.name) + ",")
builder.append(Csv.serialize(area.interactiveFlowName) + ",")
builder.append(Csv.serialize(area.flowToNextPage) + ",")
builder.append(Csv.serialize(area.position.x) + ",")
diff --git a/migration-examples/src/main/groovy/com/quadient/migration/example/common/mapping/AreasImport.groovy b/migration-examples/src/main/groovy/com/quadient/migration/example/common/mapping/AreasImport.groovy
index e756eca..6ceafa9 100644
--- a/migration-examples/src/main/groovy/com/quadient/migration/example/common/mapping/AreasImport.groovy
+++ b/migration-examples/src/main/groovy/com/quadient/migration/example/common/mapping/AreasImport.groovy
@@ -1,13 +1,12 @@
//! ---
//! displayName: Import Areas
//! category: Mapping
-//! description: Import areas with modified interactive flow names to their respective pages
+//! description: Import areas with modified interactive flow names to their respective pages and templates
//! target: gradle
//! ---
package com.quadient.migration.example.common.mapping
import com.quadient.migration.api.Migration
-import com.quadient.migration.api.dto.migrationmodel.Area
import com.quadient.migration.api.dto.migrationmodel.DocumentObject
import com.quadient.migration.api.dto.migrationmodel.MappingItem
import com.quadient.migration.example.common.util.Csv
@@ -26,27 +25,29 @@ static void run(Migration migration, Path path) {
def fileLines = path.toFile().readLines()
def columnNames = Csv.parseColumnNames(fileLines.removeFirst()).collect { Mapping.normalizeHeader(it) }
- DocumentObject currentPage = null
+ DocumentObject currentDocumentObject = null
MappingItem.Area mapping = null
int areaIndex = 0
for (line in fileLines) {
def values = Csv.getCells(line, columnNames)
def pageId = Csv.deserialize(values.get("pageId"), String.class)
+ def templateId = Csv.deserialize(values.get("templateId"), String.class)
+ def documentObjectId = pageId ?: templateId
- if (currentPage?.id != pageId) {
- if (currentPage != null) {
- migration.mappingRepository.upsert(currentPage.id, mapping)
- migration.mappingRepository.applyAreaMapping(currentPage.id)
+ if (currentDocumentObject?.id != documentObjectId) {
+ if (currentDocumentObject != null) {
+ migration.mappingRepository.upsert(currentDocumentObject.id, mapping)
+ migration.mappingRepository.applyAreaMapping(currentDocumentObject.id)
}
- def pageModel = migration.documentObjectRepository.find(pageId)
- if (!pageModel) {
- throw new IllegalStateException("Page '${pageId}' not found.")
+ def documentObjectModel = migration.documentObjectRepository.find(documentObjectId)
+ if (!documentObjectModel) {
+ throw new IllegalStateException("Document object '${documentObjectId}' not found.")
}
- mapping = migration.mappingRepository.getAreaMapping(pageId)
- currentPage = pageModel
+ mapping = migration.mappingRepository.getAreaMapping(documentObjectId)
+ currentDocumentObject = documentObjectModel
areaIndex = 0
}
@@ -59,8 +60,8 @@ static void run(Migration migration, Path path) {
areaIndex++
}
- if (currentPage != null) {
- migration.mappingRepository.upsert(currentPage.id, mapping)
- migration.mappingRepository.applyAreaMapping(currentPage.id)
+ if (currentDocumentObject != null) {
+ migration.mappingRepository.upsert(currentDocumentObject.id, mapping)
+ migration.mappingRepository.applyAreaMapping(currentDocumentObject.id)
}
}
diff --git a/migration-examples/src/test/groovy/AreasExportTest.groovy b/migration-examples/src/test/groovy/AreasExportTest.groovy
index 0e5ea34..ba4a53c 100644
--- a/migration-examples/src/test/groovy/AreasExportTest.groovy
+++ b/migration-examples/src/test/groovy/AreasExportTest.groovy
@@ -45,7 +45,7 @@ class AreasExportTest {
AreasExport.run(migration, mappingFile)
def expected = """\
- templateId (read-only),templateName (read-only),pageId,pageName (read-only),interactiveFlowName,flowToNextPage,x (read-only),y (read-only),width (read-only),height (read-only),contentPreview (read-only)
+ templateId,templateName (read-only),pageId,pageName (read-only),interactiveFlowName,flowToNextPage,x (read-only),y (read-only),width (read-only),height (read-only),contentPreview (read-only)
full tmpl,,full page,,test flow2,false,0mm,0mm,0mm,0mm,
full tmpl,,full page,,test flow3,true,0mm,0mm,0mm,0mm,
full tmpl,,full page,,,false,0mm,0mm,0mm,0mm,
@@ -55,6 +55,27 @@ class AreasExportTest {
Assertions.assertEquals(expected, mappingFile.toFile().text.replaceAll("\\r\\n|\\r", "\n"))
}
+ @Test
+ void exportTemplateDirectAreas() {
+ Path mappingFile = Paths.get(dir.path, "testProject.csv")
+ when(migration.mappingRepository.getAreaMapping(any())).thenReturn(new MappingItem.Area(null, [:], [:]))
+ when((migration.documentObjectRepository as DocumentObjectRepository).list(any())).thenReturn([
+ new DocumentObjectBuilder("tmpl with areas", DocumentObjectType.Template)
+ .content([createArea("Address Content"), createArea(null, true), createArea("Footer")])
+ .build(),
+ ])
+
+ AreasExport.run(migration, mappingFile)
+
+ def expected = """\
+ templateId,templateName (read-only),pageId,pageName (read-only),interactiveFlowName,flowToNextPage,x (read-only),y (read-only),width (read-only),height (read-only),contentPreview (read-only)
+ tmpl with areas,,,,Address Content,false,0mm,0mm,0mm,0mm,
+ tmpl with areas,,,,,true,0mm,0mm,0mm,0mm,
+ tmpl with areas,,,,Footer,false,0mm,0mm,0mm,0mm,
+ """.stripIndent()
+ Assertions.assertEquals(expected, mappingFile.toFile().text.replaceAll("\\r\\n|\\r", "\n"))
+ }
+
static Area createArea(String flowName, Boolean flowToNextPage = false) {
def areaBuilder = new AreaBuilder()
.position(new Position(Size.ofMillimeters(0), Size.ofMillimeters(0), Size.ofMillimeters(0), Size.ofMillimeters(0)))
diff --git a/migration-examples/src/test/groovy/AreasImportTest.groovy b/migration-examples/src/test/groovy/AreasImportTest.groovy
index 798b24f..a660e09 100644
--- a/migration-examples/src/test/groovy/AreasImportTest.groovy
+++ b/migration-examples/src/test/groovy/AreasImportTest.groovy
@@ -63,6 +63,32 @@ class AreasImportTest {
verify(migration.mappingRepository).applyAreaMapping("page3")
}
+ @Test
+ void importTemplateDirectAreas() {
+ Path mappingFile = Paths.get(dir.path, "testProject.csv")
+
+ when(migration.mappingRepository.getAreaMapping("tmpl1")).thenReturn(new MappingItem.Area(null, [:], [:]))
+
+ when(migration.documentObjectRepository.find("tmpl1")).thenReturn(
+ new DocumentObjectBuilder("tmpl1", DocumentObjectType.Template)
+ .content([createArea("Address Content", false), createArea(null, false), createArea("Footer", false)])
+ .build()
+ )
+
+ def input = """\
+ templateId,templateName,pageId,pageName,interactiveFlowName,flowToNextPage,x,y,width,height,contentPreview
+ tmpl1,,,,Updated Address,true,0.0mm,0.0mm,0.0mm,0.0mm,
+ tmpl1,,,,New Header,false,0.0mm,0.0mm,0.0mm,0.0mm,
+ tmpl1,,,,Footer,true,0.0mm,0.0mm,0.0mm,0.0mm,
+ """.stripIndent()
+ mappingFile.toFile().write(input)
+
+ AreasImport.run(migration, mappingFile)
+
+ verify(migration.mappingRepository).upsert("tmpl1", new MappingItem.Area(null, [0: "Updated Address", 1: "New Header", 2: "Footer"], [0: true, 1: false, 2: true]))
+ verify(migration.mappingRepository).applyAreaMapping("tmpl1")
+ }
+
static Area createArea(String flowName, boolean flowToNextPage) {
def areaBuilder = new AreaBuilder()
.position(new Position(Size.ofMillimeters(0), Size.ofMillimeters(0), Size.ofMillimeters(0), Size.ofMillimeters(0)))
diff --git a/migration-library/src/main/kotlin/com/quadient/migration/api/dto/migrationmodel/builder/documentcontent/TableBuilder.kt b/migration-library/src/main/kotlin/com/quadient/migration/api/dto/migrationmodel/builder/documentcontent/TableBuilder.kt
index 93202d9..ae5f304 100644
--- a/migration-library/src/main/kotlin/com/quadient/migration/api/dto/migrationmodel/builder/documentcontent/TableBuilder.kt
+++ b/migration-library/src/main/kotlin/com/quadient/migration/api/dto/migrationmodel/builder/documentcontent/TableBuilder.kt
@@ -11,6 +11,7 @@ import com.quadient.migration.api.dto.migrationmodel.TableRow as TableRowModel
import com.quadient.migration.shared.BorderOptions
import com.quadient.migration.shared.CellAlignment
import com.quadient.migration.shared.CellHeight
+import com.quadient.migration.shared.CellOverflow
import com.quadient.migration.shared.VariablePath
import com.quadient.migration.shared.LiteralPath
import com.quadient.migration.shared.Size
@@ -189,12 +190,14 @@ class TableBuilder : RowBuilderBase, HasBorder {
var height: CellHeight? = null
override var border: BorderOptions? = null
var alignment: CellAlignment? = null
+ var overflow: CellOverflow? = null
fun mergeLeft(value: Boolean) = apply { mergeLeft = value }
fun mergeUp(value: Boolean) = apply { mergeUp = value }
fun heightFixed(size: Size) = apply { height = CellHeight.Fixed(size) }
fun heightCustom(minHeight: Size, maxHeight: Size) = apply { height = CellHeight.Custom(minHeight, maxHeight) }
fun alignment(alignment: CellAlignment) = apply { this.alignment = alignment }
+ fun overflow(overflow: CellOverflow) = apply { this.overflow = overflow }
fun build(): Table.Cell {
return Table.Cell(
@@ -204,6 +207,7 @@ class TableBuilder : RowBuilderBase, HasBorder {
height = height,
border = border,
alignment = alignment,
+ overflow = overflow,
)
}
}
diff --git a/migration-library/src/main/kotlin/com/quadient/migration/api/dto/migrationmodel/documentcontent/Table.kt b/migration-library/src/main/kotlin/com/quadient/migration/api/dto/migrationmodel/documentcontent/Table.kt
index ef630d6..eac1e67 100644
--- a/migration-library/src/main/kotlin/com/quadient/migration/api/dto/migrationmodel/documentcontent/Table.kt
+++ b/migration-library/src/main/kotlin/com/quadient/migration/api/dto/migrationmodel/documentcontent/Table.kt
@@ -4,6 +4,7 @@ import com.quadient.migration.persistence.migrationmodel.TableEntity
import com.quadient.migration.shared.BorderOptions
import com.quadient.migration.shared.CellAlignment
import com.quadient.migration.shared.CellHeight
+import com.quadient.migration.shared.CellOverflow
import com.quadient.migration.shared.VariablePath
import com.quadient.migration.shared.Size
import com.quadient.migration.shared.TableAlignment
@@ -126,6 +127,7 @@ data class Table(
val height: CellHeight?,
val border: BorderOptions? = null,
val alignment: CellAlignment? = null,
+ val overflow: CellOverflow? = null,
) : RefValidatable {
override fun collectRefs(): List[ {
return content.flatMap {
@@ -145,6 +147,7 @@ data class Table(
height = cell.height,
border = cell.border,
alignment = cell.alignment,
+ overflow = cell.overflow,
)
}
}
@@ -157,6 +160,7 @@ data class Table(
height = height,
border = border,
alignment = alignment,
+ overflow = overflow,
)
}
}
diff --git a/migration-library/src/main/kotlin/com/quadient/migration/persistence/migrationmodel/DocumentContentEntity.kt b/migration-library/src/main/kotlin/com/quadient/migration/persistence/migrationmodel/DocumentContentEntity.kt
index ebd3dde..fa112ad 100644
--- a/migration-library/src/main/kotlin/com/quadient/migration/persistence/migrationmodel/DocumentContentEntity.kt
+++ b/migration-library/src/main/kotlin/com/quadient/migration/persistence/migrationmodel/DocumentContentEntity.kt
@@ -3,6 +3,7 @@ package com.quadient.migration.persistence.migrationmodel
import com.quadient.migration.shared.BorderOptions
import com.quadient.migration.shared.CellAlignment
import com.quadient.migration.shared.CellHeight
+import com.quadient.migration.shared.CellOverflow
import com.quadient.migration.shared.Color
import com.quadient.migration.shared.VariablePath
import com.quadient.migration.shared.Position
@@ -64,6 +65,7 @@ data class TableEntity(
val height: CellHeight? = null,
val border: BorderOptions? = null,
val alignment: CellAlignment? = null,
+ val overflow: CellOverflow? = null,
)
@Serializable
diff --git a/migration-library/src/main/kotlin/com/quadient/migration/service/deploy/InteractiveDeployClient.kt b/migration-library/src/main/kotlin/com/quadient/migration/service/deploy/InteractiveDeployClient.kt
index 6c540f7..89d93b3 100644
--- a/migration-library/src/main/kotlin/com/quadient/migration/service/deploy/InteractiveDeployClient.kt
+++ b/migration-library/src/main/kotlin/com/quadient/migration/service/deploy/InteractiveDeployClient.kt
@@ -39,6 +39,7 @@ import com.quadient.migration.service.ipsclient.OperationResult
import com.quadient.migration.service.resolveTarget
import com.quadient.migration.shared.IcmPath
import com.quadient.migration.shared.Jrd
+import com.quadient.migration.shared.DocumentObjectType
import kotlin.time.Clock
import org.jetbrains.exposed.v1.core.and
import org.jetbrains.exposed.v1.core.eq
@@ -88,14 +89,17 @@ class InteractiveDeployClient(
}
override fun shouldIncludeDependency(documentObject: DocumentObject): Boolean {
- return documentObject.internal != true
+ return documentObject.type != DocumentObjectType.Page && documentObject.internal != true
}
override fun getAllDocumentObjectsToDeploy(): List {
return documentObjectRepository.list(
- DocumentObjectTable.skip.extract("skipped") eq "false" and DocumentObjectTable.internal.eq(
- false
- )
+ (DocumentObjectTable.type inList listOf(
+ DocumentObjectType.Template.toString(),
+ DocumentObjectType.Block.toString(),
+ DocumentObjectType.Section.toString(),
+ DocumentObjectType.Snippet.toString()
+ ) and DocumentObjectTable.internal.eq(false) and (DocumentObjectTable.skip.extract("skipped") eq "false"))
)
}
@@ -127,7 +131,7 @@ class InteractiveDeployClient(
}
require(error.isEmpty()) { error }
- return documentObjects
+ return documentObjects.filter { it.type != DocumentObjectType.Page }
}
private fun deployDisplayRules(
diff --git a/migration-library/src/main/kotlin/com/quadient/migration/service/inspirebuilder/InspireDocumentObjectBuilder.kt b/migration-library/src/main/kotlin/com/quadient/migration/service/inspirebuilder/InspireDocumentObjectBuilder.kt
index 65e7627..6560681 100644
--- a/migration-library/src/main/kotlin/com/quadient/migration/service/inspirebuilder/InspireDocumentObjectBuilder.kt
+++ b/migration-library/src/main/kotlin/com/quadient/migration/service/inspirebuilder/InspireDocumentObjectBuilder.kt
@@ -51,6 +51,7 @@ import com.quadient.migration.shared.AttachmentType
import com.quadient.migration.shared.BorderOptions
import com.quadient.migration.shared.CellAlignment
import com.quadient.migration.shared.CellHeight
+import com.quadient.migration.shared.CellOverflow
import com.quadient.migration.shared.Function
import com.quadient.migration.shared.Group
import com.quadient.migration.shared.IcmPath
@@ -408,7 +409,7 @@ abstract class InspireDocumentObjectBuilder(
val singleFlow = if (this.size == 1) {
this[0]
} else {
- val sectionFlow = layout.addFlow().setType(Flow.Type.SIMPLE).setSectionFlow(true)
+ val sectionFlow = layout.addFlow().setType(Flow.Type.SIMPLE).setSectionFlow(true).setWebEditingType(SECTION)
flowName?.let { sectionFlow.setName(it) }
val sectionFlowText = sectionFlow.addParagraph().addText()
@@ -655,7 +656,8 @@ abstract class InspireDocumentObjectBuilder(
protected fun getOrBuildImage(layout: Layout, imageModel: Image, alternateText: String? = null): WfdXmlImage {
val image = getImageByName(layout, imageModel.nameOrId()) ?: layout.addImage().setName(imageModel.nameOrId())
- .setImageLocation(getImagePath(imageModel).toString(), LocationType.ICM)
+ .setImageLocation(getImagePath(imageModel).toString(), LocationType.ICM).setUseResizeWidth(true)
+ .setUseResizeHeight(true)
val options = imageModel.options
if (options != null) {
@@ -1125,15 +1127,13 @@ abstract class InspireDocumentObjectBuilder(
val cellContentFlow = buildDocumentContentAsSingleFlow(
layout, variableStructure, cellModel.content, null, null, languages
)
- val cellFlow =
- if (cellContentFlow.type === Flow.Type.SELECT_BY_INLINE_CONDITION || cellContentFlow.type === Flow.Type.SELECT_BY_CONDITION) {
- layout.addFlow().setType(Flow.Type.SIMPLE).setSectionFlow(true)
- .setWebEditingType(SECTION)
+ val cellFlow = if (cellContentFlow.type !== Flow.Type.SIMPLE) {
+ layout.addFlow().setType(Flow.Type.SIMPLE).setSectionFlow(true).setWebEditingType(SECTION)
.also { it.addParagraph().addText().appendFlow(cellContentFlow) }
} else cellContentFlow
val cell = layout.addCell().setSpanLeft(cellModel.mergeLeft).setSpanUp(cellModel.mergeUp)
- .setFlowToNextPage(true).setFlow(cellFlow)
+ .setFlowToNextPage(cellModel.overflow != CellOverflow.MoveCellToNextPage).setFlow(cellFlow)
when (cellModel.height) {
is CellHeight.Custom -> {
diff --git a/migration-library/src/main/kotlin/com/quadient/migration/service/inspirebuilder/InteractiveDocumentObjectBuilder.kt b/migration-library/src/main/kotlin/com/quadient/migration/service/inspirebuilder/InteractiveDocumentObjectBuilder.kt
index 2286cd6..f0b152f 100644
--- a/migration-library/src/main/kotlin/com/quadient/migration/service/inspirebuilder/InteractiveDocumentObjectBuilder.kt
+++ b/migration-library/src/main/kotlin/com/quadient/migration/service/inspirebuilder/InteractiveDocumentObjectBuilder.kt
@@ -32,6 +32,7 @@ import com.quadient.migration.shared.ImageType
import com.quadient.migration.shared.orDefault
import com.quadient.wfdxml.WfdXmlBuilder
import com.quadient.wfdxml.api.layoutnodes.Flow
+import com.quadient.wfdxml.api.layoutnodes.Flow.WebEditingType.SECTION
import com.quadient.wfdxml.api.layoutnodes.Image as WfdXmlImage
import com.quadient.wfdxml.api.layoutnodes.data.DataType
import com.quadient.wfdxml.api.layoutnodes.data.VariableKind
@@ -239,42 +240,30 @@ class InteractiveDocumentObjectBuilder(
variableStructure
)
- DocumentObjectType.Page -> {
- documentObject.content.paragraphIfEmpty().forEach {
- if (it is Area && !it.interactiveFlowName.isNullOrBlank()) {
- val flowName = it.interactiveFlowName!!
- val interactiveFlowId = if (flowName.startsWith("Def.")) {
- flowName
+ else -> {
+ documentObject.content.paragraphIfEmpty().forEach { documentContentPart ->
+ if (documentContentPart is DocumentObjectRef) {
+ val referencedModel = documentObjectRepository.findOrFail(documentContentPart.id)
+ if (referencedModel.type == DocumentObjectType.Page) {
+ referencedModel.content.paragraphIfEmpty().forEach { pageContentPart ->
+ mapContentItemToInteractiveFlow(pageContentPart, currentBaseTemplateData, interactiveFlowsWithContent)
+ }
} else {
- currentBaseTemplateData.interactiveFlowNamesToIds[flowName]
- }
-
- if (interactiveFlowId.isNullOrBlank()) {
- val errorMessage =
- "Failed to find interactive flow '$flowName' in base template '$baseTemplatePath'."
- logger.error(errorMessage)
- error(errorMessage)
+ interactiveFlowsWithContent.getOrPut(mainFlowId) { mutableListOf() }.add(documentContentPart)
}
-
- val interactiveFlowContent =
- interactiveFlowsWithContent.getOrPut(interactiveFlowId) { mutableListOf() }
- interactiveFlowContent.addAll(it.content)
} else {
- val interactiveFlowContent = interactiveFlowsWithContent.getOrPut(mainFlowId) { mutableListOf() }
- interactiveFlowContent.add(it)
+ mapContentItemToInteractiveFlow(documentContentPart, currentBaseTemplateData, interactiveFlowsWithContent)
}
}
}
- else -> {
- interactiveFlowsWithContent[mainFlowId] = documentObject.content.toMutableList()
- }
}
val hasMultipleFlows = interactiveFlowsWithContent.size > 1
interactiveFlowsWithContent.forEach {
val interactiveFlowText =
- layout.addFlow().setId(it.key).setType(Flow.Type.SIMPLE).setSectionFlow(true).addParagraph().addText()
+ layout.addFlow().setId(it.key).setType(Flow.Type.SIMPLE).setSectionFlow(true).setWebEditingType(SECTION)
+ .addParagraph().addText()
val flowName = if (hasMultipleFlows && it.key != mainFlowId) {
val interactiveFlowName =
@@ -330,7 +319,7 @@ class InteractiveDocumentObjectBuilder(
}
override fun shouldIncludeInternalDependency(documentObject: DocumentObject): Boolean {
- return documentObject.internal == true
+ return documentObject.internal == true || documentObject.type == DocumentObjectType.Page
}
override fun resolveParagraphStyleName(name: String): String =
@@ -342,6 +331,31 @@ class InteractiveDocumentObjectBuilder(
override fun resolveTableStyleName(name: String): String =
styleDefinitionData?.tableStyleDisplayNamesToName?.get(name) ?: name
+ private fun mapContentItemToInteractiveFlow(
+ contentItem: DocumentContent,
+ baseTemplateData: BaseTemplateData,
+ interactiveFlowsWithContent: MutableMap>,
+ ) {
+ if (contentItem is Area && !contentItem.interactiveFlowName.isNullOrBlank()) {
+ val flowName = contentItem.interactiveFlowName!!
+ val interactiveFlowId = if (flowName.startsWith("Def.")) {
+ flowName
+ } else {
+ baseTemplateData.interactiveFlowNamesToIds[flowName]
+ }
+
+ if (interactiveFlowId.isNullOrBlank()) {
+ val errorMessage = "Failed to find interactive flow '$flowName' in the base template."
+ logger.error(errorMessage)
+ error(errorMessage)
+ }
+
+ interactiveFlowsWithContent.getOrPut(interactiveFlowId) { mutableListOf() }.addAll(contentItem.content)
+ } else {
+ interactiveFlowsWithContent.getOrPut(mainFlowId) { mutableListOf() }.add(contentItem)
+ }
+ }
+
private fun getOrLoadBaseTemplateData(path: IcmPath): BaseTemplateData? {
if (baseTemplateCache.containsKey(path)) return baseTemplateCache[path]
diff --git a/migration-library/src/main/kotlin/com/quadient/migration/shared/TableOptions.kt b/migration-library/src/main/kotlin/com/quadient/migration/shared/TableOptions.kt
index d3a7e52..963db0e 100644
--- a/migration-library/src/main/kotlin/com/quadient/migration/shared/TableOptions.kt
+++ b/migration-library/src/main/kotlin/com/quadient/migration/shared/TableOptions.kt
@@ -17,6 +17,15 @@ enum class CellAlignment {
Bottom,
}
+@Serializable
+enum class CellOverflow {
+ /** Overflow cell content to next page (default). Maps to {@code FlowToNextPage=True}. */
+ OverflowContentToNextPage,
+
+ /** Move cell to next page. Maps to {@code FlowToNextPage=False}. */
+ MoveCellToNextPage,
+}
+
@Serializable
sealed interface CellHeight {
@Serializable
diff --git a/migration-library/src/test/kotlin/com/quadient/migration/service/deploy/InteractiveDeployClientTest.kt b/migration-library/src/test/kotlin/com/quadient/migration/service/deploy/InteractiveDeployClientTest.kt
index 37df8a7..21d0ea3 100644
--- a/migration-library/src/test/kotlin/com/quadient/migration/service/deploy/InteractiveDeployClientTest.kt
+++ b/migration-library/src/test/kotlin/com/quadient/migration/service/deploy/InteractiveDeployClientTest.kt
@@ -115,7 +115,8 @@ class InteractiveDeployClientTest {
@BeforeEach
fun setupAll() {
every { documentObjectBuilder.shouldIncludeInternalDependency(any()) } answers {
- firstArg().internal ?: false
+ val documentObject = firstArg()
+ (documentObject.internal ?: false) || documentObject.type == DocumentObjectType.Page
}
every { ipsService.writeMetadata(any()) } just runs
every { ipsService.setProductionApprovalState(any]>()) } returns OperationResult.Success
@@ -622,6 +623,61 @@ class InteractiveDeployClientTest {
verify(exactly = 1) { documentObjectRepository.list(any>()) }
}
+ @Test
+ fun `page objects are silently filtered from deploy list`() {
+ val spy = spyk(subject)
+ every { spy.deployDocumentObjectsInternal(any(), any(), any(), any(), any(), any()) } returns DeploymentResult(
+ Uuid.random()
+ )
+ every { documentObjectRepository.list(any>()) } returns listOf(
+ aBlock(id = "1", type = DocumentObjectType.Block),
+ aBlock(id = "2", type = DocumentObjectType.Page),
+ aBlock(id = "3", type = DocumentObjectType.Template),
+ aBlock(id = "4", type = DocumentObjectType.Section),
+ )
+
+ spy.deployDocumentObjects(listOf("1", "2", "3", "4"))
+
+ verify(exactly = 1) { documentObjectRepository.list(any>()) }
+ verify {
+ spy.deployDocumentObjectsInternal(match { docObjects ->
+ docObjects.size == 3 && docObjects.map { it.id }.containsAll(listOf("1", "3", "4"))
+ }, any(), any(), any(), any(), any())
+ }
+ }
+
+ @Test
+ fun `deploy list of document objects excludes pages but includes their transitive external dependencies`() {
+ val spy = spyk(subject)
+ every { spy.deployDocumentObjectsInternal(any(), any(), any(), any(), any(), any()) } returns DeploymentResult(
+ Uuid.random()
+ )
+
+ val block3 = aDocObj("block3", DocumentObjectType.Block)
+ val block2 = aDocObj("block2", DocumentObjectType.Block, internal = true, content = listOf(aDocumentObjectRef(block3.id)))
+ val block1 = aDocObj("block1", DocumentObjectType.Block)
+ val page = aDocObj("page1", DocumentObjectType.Page, content = listOf(aDocumentObjectRef(block1.id), aDocumentObjectRef(block2.id)))
+ val template = aDocObj("template1", DocumentObjectType.Template, content = listOf(aDocumentObjectRef(page.id)))
+
+ every { documentObjectRepository.list(any>()) } returns listOf(template)
+ every { documentObjectRepository.findOrFail("page1") } returns page
+ every { documentObjectRepository.findOrFail("block1") } returns block1
+ every { documentObjectRepository.findOrFail("block2") } returns block2
+ every { documentObjectRepository.findOrFail("block3") } returns block3
+
+ spy.deployDocumentObjects(listOf("template1"), false)
+
+ verify {
+ spy.deployDocumentObjectsInternal(match { docObjects ->
+ val ids = docObjects.map { it.id }
+ ids.containsAll(listOf("template1", "block1", "block3"))
+ && !ids.contains("page1")
+ && !ids.contains("block2")
+ }, any(), any(), any(), any(), any())
+ }
+ }
+
+
@Test
fun `deploy list of document objects without dependencies`() {
val spy = spyk(subject)
diff --git a/migration-library/src/test/kotlin/com/quadient/migration/service/inspirebuilder/InteractiveDocumentObjectBuilderTest.kt b/migration-library/src/test/kotlin/com/quadient/migration/service/inspirebuilder/InteractiveDocumentObjectBuilderTest.kt
index e98b48d..e0ba6a6 100644
--- a/migration-library/src/test/kotlin/com/quadient/migration/service/inspirebuilder/InteractiveDocumentObjectBuilderTest.kt
+++ b/migration-library/src/test/kotlin/com/quadient/migration/service/inspirebuilder/InteractiveDocumentObjectBuilderTest.kt
@@ -5,16 +5,13 @@ import com.quadient.migration.api.InspireOutput
import com.quadient.migration.api.PathsConfig
import com.quadient.migration.api.ProjectConfig
import com.quadient.migration.api.dto.migrationmodel.DisplayRule
-import com.quadient.migration.api.dto.migrationmodel.DisplayRuleRef
+import com.quadient.migration.api.dto.migrationmodel.DocumentContent
import com.quadient.migration.api.dto.migrationmodel.DocumentObject
-import com.quadient.migration.api.dto.migrationmodel.FirstMatch
import com.quadient.migration.api.dto.migrationmodel.Image
import com.quadient.migration.api.dto.migrationmodel.ImageRef
import com.quadient.migration.api.dto.migrationmodel.ParagraphStyle
-import com.quadient.migration.api.dto.migrationmodel.ParagraphStyleRef
import com.quadient.migration.api.dto.migrationmodel.StringValue
import com.quadient.migration.api.dto.migrationmodel.Tab
-import com.quadient.migration.api.dto.migrationmodel.Table
import com.quadient.migration.api.dto.migrationmodel.Tabs
import com.quadient.migration.api.dto.migrationmodel.TextStyle
import com.quadient.migration.api.dto.migrationmodel.Variable
@@ -22,10 +19,13 @@ import com.quadient.migration.api.dto.migrationmodel.VariableRef
import com.quadient.migration.api.dto.migrationmodel.VariableStructure
import com.quadient.migration.api.dto.migrationmodel.builder.DisplayRuleBuilder
import com.quadient.migration.api.dto.migrationmodel.builder.DocumentObjectBuilder
+import com.quadient.migration.api.dto.migrationmodel.builder.ImageBuilder
+import com.quadient.migration.api.dto.migrationmodel.builder.ParagraphBuilder
import com.quadient.migration.api.dto.migrationmodel.builder.ParagraphStyleBuilder
import com.quadient.migration.api.dto.migrationmodel.builder.TextStyleBuilder
import com.quadient.migration.api.dto.migrationmodel.builder.VariableBuilder
import com.quadient.migration.api.dto.migrationmodel.builder.VariableStructureBuilder
+import com.quadient.migration.api.dto.migrationmodel.builder.documentcontent.AreaBuilder
import com.quadient.migration.api.repository.AttachmentRepository
import com.quadient.migration.api.repository.DisplayRuleRepository
import com.quadient.migration.api.repository.DocumentObjectRepository
@@ -39,6 +39,7 @@ import com.quadient.migration.service.ipsclient.IpsService
import com.quadient.migration.shared.Alignment
import com.quadient.migration.shared.BinOp.*
import com.quadient.migration.shared.DataType
+import com.quadient.migration.shared.DocumentObjectType
import com.quadient.migration.shared.DocumentObjectType.*
import com.quadient.migration.shared.AttachmentType
import com.quadient.migration.shared.IcmPath
@@ -50,20 +51,18 @@ import com.quadient.migration.shared.LiteralDataType
import com.quadient.migration.shared.Size
import com.quadient.migration.shared.SkipOptions
import com.quadient.migration.shared.TabType
-import com.quadient.migration.shared.TableAlignment
import com.quadient.migration.shared.VariablePathData
+import com.quadient.migration.shared.centimeters
+import com.quadient.migration.shared.millimeters
import com.quadient.migration.shared.toIcmPath
-import com.quadient.migration.tools.aCell
import com.quadient.migration.tools.model.aBlock
import com.quadient.migration.tools.model.aDisplayRule
import com.quadient.migration.tools.model.aParagraph
import com.quadient.migration.tools.aProjectConfig
-import com.quadient.migration.tools.model.aCell
import com.quadient.migration.tools.model.aDocObj
import com.quadient.migration.tools.model.aDocumentObjectRef
import com.quadient.migration.tools.model.aAttachment
import com.quadient.migration.tools.model.aImage
-import com.quadient.migration.tools.model.aRow
import com.quadient.migration.tools.model.aSelectByLanguage
import com.quadient.migration.tools.model.aTemplate
import com.quadient.migration.tools.model.aText
@@ -71,7 +70,6 @@ import com.quadient.migration.tools.model.aTextDef
import com.quadient.migration.tools.model.aTextStyle
import com.quadient.migration.tools.model.aVariable
import com.quadient.migration.tools.model.aVariableStructure
-import com.quadient.migration.tools.model.anArea
import com.quadient.migration.tools.shouldBeEqualTo
import com.quadient.migration.tools.shouldBeNull
import com.quadient.migration.tools.shouldBeOfSize
@@ -116,11 +114,9 @@ class InteractiveDocumentObjectBuilderTest {
@Test
fun `build of simple block with string and var ref that is not part of structure results in single flow with one paragraph and text`() {
// given
- val variable = aVariable("var1", "varName1")
- val block = aBlock(
- "1", listOf(aParagraph(aText(listOf(StringValue("some text"), VariableRef(variable.id)))))
- )
- every { variableRepository.findOrFail(eq(variable.id)) } returns variable
+ val variable = VariableBuilder("var1").name("varName1").dataType(DataType.String).build().mock()
+ val block =
+ DocumentObjectBuilder("1", Block).paragraph { text { string("some text").variableRef(variable) } }.build()
// when
val result = subject.buildDocumentObject(block).let { xmlMapper.readTree(it.trimIndent()) }
@@ -145,9 +141,11 @@ class InteractiveDocumentObjectBuilderTest {
.build()
.mock()
- val block = aBlock(
- "1", listOf(aParagraph(aText(StringValue("some text"), textStyle.id), paraStyle.id))
- )
+ val block = DocumentObjectBuilder("1", DocumentObjectType.Block).paragraph {
+ styleRef(paraStyle).text {
+ styleRef(textStyle).string("some text")
+ }
+ }.build()
// when
val result = subject.buildDocumentObject(block).let { xmlMapper.readTree(it.trimIndent()) }
@@ -227,10 +225,8 @@ class InteractiveDocumentObjectBuilderTest {
@Test
fun `build template with reference to block results in direct external flow`() {
// given
- val block = aBlock("1", listOf(aParagraph(aText(StringValue("Hello")))))
- val template = aTemplate("2", listOf(aDocumentObjectRef(block.id)))
-
- every { documentObjectRepository.findOrFail(block.id) } returns block
+ val block = DocumentObjectBuilder("1", Block).string("Hello").build().mock()
+ val template = DocumentObjectBuilder("2", Template).documentObjectRef(block).build()
// when
val result = subject.buildDocumentObject(template).let { xmlMapper.readTree(it.trimIndent()) }
@@ -252,47 +248,25 @@ class InteractiveDocumentObjectBuilderTest {
@Test
fun `build block with table has correctly promoted column widths and spans`() {
// given
- val variable = aVariable("clientName")
- val block = aBlock(
- "1", listOf(
- Table(
- listOf(
- aRow(
- listOf(
- aCell(
- aParagraph(
- aText(
- listOf(
- StringValue("Hello "),
- VariableRef(variable.id),
- StringValue(" how are you?")
- )
- )
- )
- ), aCell(aParagraph(aText(StringValue("First row, second cell "))))
- )
- ), aRow(
- listOf(
- aCell(aParagraph(aText(StringValue("Second row, first cell")))),
- aCell(aParagraph(aText(StringValue("Second row, second cell"))), mergeLeft = true)
- )
- )
- ), columnWidths = listOf(
- Table.ColumnWidth(Size.ofMillimeters(150), 10.0),
- Table.ColumnWidth(Size.ofCentimeters(3), 1.0)
- ),
- firstHeader = emptyList(),
- footer = emptyList(),
- lastFooter = emptyList(),
- minWidth = null,
- maxWidth = null,
- percentWidth = null,
- border = null,
- alignment = TableAlignment.Left,
- )
- )
- )
- every { variableRepository.findOrFail(eq(variable.id)) } returns variable
+ val variable = VariableBuilder("clientName").dataType(DataType.String).build().mock()
+ val block = DocumentObjectBuilder("1", Block).table {
+ addRow {
+ addCell {
+ paragraph {
+ text {
+ string("Hello ").variableRef(variable).string(" how are you?")
+ }
+ }
+ }
+ addCell { string("First row, second cell") }
+ }
+ addRow {
+ addCell { string("Second row, first cell") }
+ addCell { string("Second row, second cell").mergeLeft(true) }
+ }
+ addColumnWidth(150.millimeters(), 10.0)
+ addColumnWidth(3.centimeters(), 1.0)
+ }.build()
// when
val result = subject.buildDocumentObject(block).let { xmlMapper.readTree(it.trimIndent()) }
@@ -321,21 +295,12 @@ class InteractiveDocumentObjectBuilderTest {
@Test
fun `build of more nested and complex structure is correctly wrapped into section if required`() {
// given
- val externalBlock = aBlock("1", listOf(aParagraph(aText(StringValue("Hello")))))
- val block = aBlock("2", listOf(aParagraph(aText(StringValue("Sir")))), internal = true)
-
- val section = aBlock(
- "5", type = Section, content = listOf(
- aDocumentObjectRef(externalBlock.id),
- aParagraph(aText(StringValue("In between"))),
- aDocumentObjectRef(block.id)
- ), internal = true
- )
- val template = aTemplate("10", listOf(aDocumentObjectRef(section.id)))
+ val externalBlock = DocumentObjectBuilder("1", Block).string("Hello").build().mock()
+ val block = DocumentObjectBuilder("2", Block).string("Sir").internal(true).build().mock()
- every { documentObjectRepository.findOrFail(externalBlock.id) } returns externalBlock
- every { documentObjectRepository.findOrFail(block.id) } returns block
- every { documentObjectRepository.findOrFail(section.id) } returns section
+ val section = DocumentObjectBuilder("5", Section).documentObjectRef(externalBlock).string("In between")
+ .documentObjectRef(block).internal(true).build().mock()
+ val template = DocumentObjectBuilder("10", Template).documentObjectRef(section).build()
// when
val result = subject.buildDocumentObject(template).let { xmlMapper.readTree(it.trimIndent()) }
@@ -373,29 +338,25 @@ class InteractiveDocumentObjectBuilderTest {
@Test
fun `build block with variable refs in variable structure with converted value based on type`() {
// given
- val longVar = aVariable("var1", "varName1", dataType = DataType.Integer64, defaultValue = "2025").mock()
- val currencyVar = aVariable("var2", "varName2", dataType = DataType.Currency, defaultValue = "249.99").mock()
- val boolVar = aVariable("var3", "varName3", dataType = DataType.Boolean, defaultValue = "TRUE").mock()
- val variableStructure = aVariableStructure(
- structure = mapOf(
- longVar.id to VariablePathData("Data.Clients.Value"),
- currencyVar.id to VariablePathData("Data.Clients.Value", "Money"),
- boolVar.id to VariablePathData("Data.Clients.Value")
- )
- ).mock()
+ val longVar =
+ VariableBuilder("var1").name("varName1").dataType(DataType.Integer64).defaultValue("2025").build().mock()
+ val currencyVar =
+ VariableBuilder("var2").name("varName2").dataType(DataType.Currency).defaultValue("249.99").build().mock()
+ val boolVar =
+ VariableBuilder("var3").name("varName3").dataType(DataType.Boolean).defaultValue("TRUE").build().mock()
+ val variableStructure = VariableStructureBuilder("vs1").addVariable(longVar.id, "Data.Clients.Value")
+ .addVariable(currencyVar.id, "Data.Clients.Value", "Money").addVariable(boolVar.id, "Data.Clients.Value")
+ .build().mock()
+
val config = aProjectConfig(defaultVariableStructure = variableStructure.id)
- val block = aBlock(
- "1", listOf(
- aParagraph(
- aText(
- listOf(
- VariableRef(longVar.id), VariableRef(currencyVar.id), VariableRef(boolVar.id)
- )
- )
- )
- )
- )
+ val block = DocumentObjectBuilder("1", Block).paragraph {
+ text {
+ variableRef(longVar)
+ variableRef(currencyVar)
+ variableRef(boolVar)
+ }
+ }.build()
// when
val subject = aSubject(config)
@@ -435,14 +396,10 @@ class InteractiveDocumentObjectBuilderTest {
@Test
fun `build template with external block using display rule wraps the block in condition flow`() {
// given
- val displayRule =
- aDisplayRule(Literal("A", LiteralDataType.String), Equals, Literal("B", LiteralDataType.String))
-
- val block = aBlock("1", listOf(aParagraph(aText(StringValue("Hello")))))
- val template = aTemplate("2", listOf(aDocumentObjectRef(block.id, displayRule.id)))
+ val displayRule = DisplayRuleBuilder("R_1").comparison { value("A").equals().value("B") }.build().mock()
- every { documentObjectRepository.findOrFail(block.id) } returns block
- every { displayRuleRepository.findOrFail(displayRule.id) } returns displayRule
+ val block = DocumentObjectBuilder("1", Block).string("Hello").build().mock()
+ val template = DocumentObjectBuilder("2", Template).documentObjectRef(block, displayRule).build()
// when
val result = subject.buildDocumentObject(template).let { xmlMapper.readTree(it.trimIndent()) }
@@ -528,10 +485,8 @@ class InteractiveDocumentObjectBuilderTest {
@Test
fun `build block with styled paragraph under display rule and one of its texts under display rule wraps it in multiple condition flows`() {
// given
- val variable = aVariable("V1", "900_MailCount").mock()
- val variableStructure = aVariableStructure(
- structure = mapOf(variable.id to VariablePathData("Data.1.Value"))
- ).mock()
+ val variable = VariableBuilder("V1").name("900_MailCount").dataType(DataType.String).build().mock()
+ val variableStructure = VariableStructureBuilder("VS1").addVariable(variable.id, "Data.1.Value").build().mock()
val config = aProjectConfig(defaultVariableStructure = variableStructure.id)
val textStyle = TextStyleBuilder("T1").definition { bold(true) }.build().mock()
@@ -540,32 +495,18 @@ class InteractiveDocumentObjectBuilderTest {
.build()
.mock()
- val paraDisplayRule = aDisplayRule(
- Literal(variable.id, LiteralDataType.Variable),
- GreaterOrEqualThan,
- Literal("540", LiteralDataType.Number),
- id = "R_para"
- )
- val textDisplayRule = aDisplayRule(
- Literal("A", LiteralDataType.String), NotEquals, Literal("B", LiteralDataType.String), id = "R_text"
- )
+ val paraDisplayRule =
+ DisplayRuleBuilder("R_para").comparison { variable(variable).greaterOrEqualThan().value(540.0) }.build()
+ .mock()
+ val textDisplayRule =
+ DisplayRuleBuilder("R_text").comparison { value("A").notEquals().value("B") }.build().mock()
- val block = aBlock(
- "1", listOf(
- aParagraph(
- listOf(
- aText(
- StringValue("This is")
- ), aText(
- StringValue("Preposterous!"), textStyle.id, DisplayRuleRef(textDisplayRule.id)
- )
- ), ParagraphStyleRef(paraStyle.id), DisplayRuleRef(paraDisplayRule.id)
- )
- )
- ).mock()
-
- every { displayRuleRepository.findOrFail(paraDisplayRule.id) } returns paraDisplayRule
- every { displayRuleRepository.findOrFail(textDisplayRule.id) } returns textDisplayRule
+ val block = DocumentObjectBuilder("1", Block).paragraph {
+ text { string("This is") }
+ text {
+ string("Preposterous!").styleRef(textStyle).displayRuleRef(textDisplayRule)
+ }.styleRef(paraStyle).displayRuleRef(paraDisplayRule)
+ }.build().mock()
// when
val subject = aSubject(config)
@@ -584,7 +525,7 @@ class InteractiveDocumentObjectBuilderTest {
val conditionFlow = result["Flow"].last { it["Id"].textValue() == conditionFlowRef }
conditionFlow["Type"].textValue().shouldBeEqualTo("InlCond")
val condition = conditionFlow["Condition"]
- condition["Value"].textValue().shouldBeEqualTo("return (DATA._1.Current._900_MailCount>=540);")
+ condition["Value"].textValue().shouldBeEqualTo("return (DATA._1.Current._900_MailCount>=540.0);")
val paraFlowRef = condition[""].textValue()
val paraFlow = result["Flow"].last { it["Id"].textValue() == paraFlowRef }
@@ -612,41 +553,24 @@ class InteractiveDocumentObjectBuilderTest {
@Test
fun `build block with table that has one row under display rule`() {
// given
- val displayRule = aDisplayRule(
- Literal("TRUE", LiteralDataType.Boolean), Equals, Literal("FalSe", LiteralDataType.Boolean)
- )
-
- val block = aBlock(
- "1", listOf(
- Table(
- listOf(
- aRow(
- listOf(
- aCell(listOf(aParagraph(aText(StringValue("First row, first cell"))))),
- aCell(listOf(aParagraph(aText(StringValue("First row, second cell")))))
- )
- ), aRow(
- listOf(
- aCell(listOf(aParagraph(aText(StringValue("Second row, first cell"))))),
- aCell(listOf(aParagraph(aText(StringValue("Second row, second cell")))))
- ), displayRule.id
- )
- ),
- columnWidths = listOf(),
- firstHeader = emptyList(),
- footer = emptyList(),
- lastFooter = emptyList(),
- minWidth = null,
- maxWidth = null,
- percentWidth = null,
- border = null,
- alignment = TableAlignment.Left,
- )
- )
- )
+ val displayRule = DisplayRuleBuilder("R_1").comparison {
+ value(true).equals().value(false)
+ }.build().mock()
+
+ val block = DocumentObjectBuilder("1", Block).table {
+ addRow {
+ addCell { string("First row, first cell") }
+ addCell { string("First row, second cell") }
+ }
+ addRow {
+ addCell { string("Second row, first cell") }
+ addCell { string("Second row, second cell") }
+ displayRuleRef(displayRule)
+ }
+ }.build().mock()
- every { displayRuleRepository.findOrFail(displayRule.id) } returns displayRule
- every { documentObjectRepository.find(block.id) } returns block
+ val config = aProjectConfig(defaultVariableStructure = null)
+ val subject = aSubject(config)
// when
val result = subject.buildDocumentObject(block).let { xmlMapper.readTree(it.trimIndent()) }
@@ -669,9 +593,8 @@ class InteractiveDocumentObjectBuilderTest {
@Test
fun `build of template skips unsupported block and template is created without it`() {
// given
- val unsupportedBlock = aBlock("1", skip = SkipOptions(true, null, null))
- every { documentObjectRepository.findOrFail("block1") } returns unsupportedBlock
- val template = aTemplate("10", listOf(aDocumentObjectRef("block1")))
+ val unsupportedBlock = DocumentObjectBuilder("1", Block).skip().build().mock()
+ val template = DocumentObjectBuilder("10", Template).documentObjectRef(unsupportedBlock).build()
// when
val result = subject.buildDocumentObject(template)
@@ -686,7 +609,7 @@ class InteractiveDocumentObjectBuilderTest {
@Test
fun `build block with variable ref that is not found throws exception`() {
// given
- val block = aBlock("1", listOf(aParagraph(aText(VariableRef("var1")))))
+ val block = DocumentObjectBuilder("1", Block).variableRef("var1").build()
every { variableRepository.findOrFail("var1") } throws IllegalStateException("Record 'var1' not found.")
// when
@@ -699,20 +622,14 @@ class InteractiveDocumentObjectBuilderTest {
@Test
fun `build template with block using display rule with unmapped variable creates dummy display rule`() {
// given
- val variable = aVariable("V_999", "DollarsInBank", dataType = DataType.Currency).mock()
-
- val displayRule = aDisplayRule(
- Literal(variable.id, LiteralDataType.Variable),
- GreaterOrEqualThan,
- Literal("25000", LiteralDataType.Number),
- negation = true
- ).mock()
+ val variable = VariableBuilder("V_999").name("DollarsInBank").dataType(DataType.Currency).build().mock()
- val block = aBlock("1", listOf(aParagraph(aText(StringValue("Hello"))))).mock()
- val template = aTemplate("2", listOf(aDocumentObjectRef(block.id, displayRule.id)))
+ val displayRule = DisplayRuleBuilder("R_1").group {
+ comparison { variable(variable).greaterOrEqualThan().value(25000.0) }.negate()
+ }.build().mock()
- every { variableRepository.find(variable.id) } returns variable
- every { variableStructureRepository.listAll() } returns listOf()
+ val block = DocumentObjectBuilder("1", Block).string("Hello").build().mock()
+ val template = DocumentObjectBuilder("2", Template).documentObjectRef(block, displayRule).build()
// when
val result = subject.buildDocumentObject(template).let { xmlMapper.readTree(it.trimIndent()) }
@@ -720,43 +637,26 @@ class InteractiveDocumentObjectBuilderTest {
// then
val conditionVariable = result["Variable"].last { it["Type"]?.textValue() == "Calculated" }
conditionVariable["Script"].textValue()
- .shouldBeEqualTo("return not (String('DollarsInBank>=25000')==String('unmapped'));")
+ .shouldBeEqualTo("return not (String('DollarsInBank>=25000.0')==String('unmapped'));")
}
@Test
fun `build block with paragraph containing strings and document object refs inside one paragraph text`() {
// given
- val variable = aVariable("V_100", "Salutation")
-
- val innerBlock = aBlock(
- "1", listOf(
- aParagraph(
- aText(listOf(StringValue("Dear "), VariableRef(variable.id)))
- )
- ), internal = true
- )
+ val variable = VariableBuilder("V_100").name("Salutation").dataType(DataType.String).build().mock()
- val externalBlock = aBlock("2", listOf(aParagraph(aText(StringValue("This is a good day!")))))
+ val innerBlock = DocumentObjectBuilder("1", Block).paragraph {
+ text { string("Dear ").variableRef(variable) }
+ }.internal(true).build().mock()
- val block = aBlock(
- "10", listOf(
- aParagraph(
- aText(
- listOf(
- StringValue("Hello, "),
- aDocumentObjectRef(innerBlock.id),
- StringValue(". How are you?"),
- aDocumentObjectRef(externalBlock.id)
- )
- )
- )
- )
- )
+ val externalBlock = DocumentObjectBuilder("2", Block).string("This is a good day!").build().mock()
- every { documentObjectRepository.findOrFail(innerBlock.id) } returns innerBlock
- every { documentObjectRepository.findOrFail(externalBlock.id) } returns externalBlock
- every { variableRepository.findOrFail(variable.id) } returns variable
- every { variableStructureRepository.listAll() } returns listOf()
+ val block = DocumentObjectBuilder("10", Block).paragraph {
+ text {
+ string("Hello, ").documentObjectRef(innerBlock).string(". How are you?")
+ .documentObjectRef(externalBlock)
+ }
+ }.build()
// when
val result = subject.buildDocumentObject(block).let { xmlMapper.readTree(it.trimIndent()) }
@@ -774,8 +674,9 @@ class InteractiveDocumentObjectBuilderTest {
@Test
fun `build block with image`() {
// given
- val image = aImage("Dog", options = ImageOptions(Size.ofPoints(120), Size.ofPoints(90))).mock()
- val block = aBlock("1", listOf(ImageRef(image.id)))
+ val image = ImageBuilder("Dog").name("Image_Dog").sourcePath("somePath").imageType(ImageType.Jpeg)
+ .options(ImageOptions(Size.ofPoints(120), Size.ofPoints(90))).build().mock()
+ val block = DocumentObjectBuilder("1", Block).imageRef(image).build()
// when
val result = subject.buildDocumentObject(block).let { xmlMapper.readTree(it.trimIndent()) }
@@ -784,7 +685,7 @@ class InteractiveDocumentObjectBuilderTest {
result["Image"].first()["Name"].textValue().shouldBeEqualTo("Image_Dog")
val imageContent = result["Image"].last()
imageContent["ImageLocation"].textValue()
- .shouldBeEqualTo("VCSLocation,icm://Interactive/${config.interactiveTenant}/Resources/Images/${image.sourcePath}")
+ .shouldBeEqualTo("VCSLocation,icm://Interactive/${config.interactiveTenant}/Resources/Images/${image.name}.jpg")
imageContent["UseResizeWidth"].textValue().shouldBeEqualTo("True")
imageContent["UseResizeHeight"].textValue().shouldBeEqualTo("True")
imageContent["ResizeImageWidth"].textValue().shouldBeEqualTo(image.options?.resizeWidth?.toMeters().toString())
@@ -795,8 +696,10 @@ class InteractiveDocumentObjectBuilderTest {
@Test
fun `build block with image uses alternateText from Image`() {
// given
- val image = aImage("Dog", alternateText = "A cute dog picture").mock()
- val block = aBlock("1", listOf(ImageRef(image.id)))
+ val image =
+ ImageBuilder("Dog").name("Image_Dog").sourcePath("somePath").alternateText("A cute dog picture").build()
+ .mock()
+ val block = DocumentObjectBuilder("1", Block).imageRef(image).build()
// when
val result = subject.buildDocumentObject(block).let { xmlMapper.readTree(it.trimIndent()) }
@@ -866,33 +769,19 @@ class InteractiveDocumentObjectBuilderTest {
@Test
fun `paragraph with first match is built to inline condition flow with multiple options`() {
// given
- val rule1 = aDisplayRule(
- Literal("A", LiteralDataType.String), Equals, Literal("B", LiteralDataType.String), id = "R_1"
- ).mock()
-
- val rule2 = aDisplayRule(
- Literal("C", LiteralDataType.String), Equals, Literal("C", LiteralDataType.String), id = "R_2"
- ).mock()
-
- val block = aDocObj(
- "B_1", Block, listOf(
- aParagraph(
- aText(
- listOf(
- StringValue("Hello, "), FirstMatch(
- cases = listOf(
- FirstMatch.Case(
- DisplayRuleRef(rule1.id), listOf(aParagraph(aText(StringValue("Mike")))), null
- ), FirstMatch.Case(
- DisplayRuleRef(rule2.id), listOf(aParagraph(aText(StringValue("Jon")))), null
- )
- ), emptyList()
- ), StringValue(", how are you?")
- )
- )
- )
- )
- ).mock()
+ val rule1 = DisplayRuleBuilder("R_1").comparison { value("A").equals().value("B") }.build().mock()
+ val rule2 = DisplayRuleBuilder("R_2").comparison { value("C").equals().value("C") }.build().mock()
+
+ val block = DocumentObjectBuilder(
+ "B_1", Block
+ ).paragraph {
+ text {
+ string("Hello, ").firstMatch {
+ addCase().displayRuleRef(rule1).string("Mike")
+ addCase().displayRuleRef(rule2).string("Jon")
+ }.string(", how are you?")
+ }
+ }.build()
// when
val result = subject.buildDocumentObject(block).let { xmlMapper.readTree(it.trimIndent()) }
@@ -928,12 +817,10 @@ class InteractiveDocumentObjectBuilderTest {
@Test
fun `build of flow under display rule wraps in in condition flow`() {
// given
- val rule =
- aDisplayRule(Literal("C", LiteralDataType.String), Equals, Literal("C", LiteralDataType.String)).mock()
- val innerBlock = aDocObj(
- "B_1", Block, listOf(aParagraph(aText(StringValue("Text")))), true, displayRuleRef = rule.id
- ).mock()
- val template = aDocObj("T_1", Template, listOf(aDocumentObjectRef(innerBlock.id)))
+ val rule = DisplayRuleBuilder("R_1").comparison { value("C").equals().value("C") }.build().mock()
+ val innerBlock =
+ DocumentObjectBuilder("B_1", Block).string("Text").internal(true).displayRuleRef(rule).build().mock()
+ val template = DocumentObjectBuilder("T_1", Template).documentObjectRef(innerBlock).build()
// when
val result = subject.buildDocumentObject(template).let { xmlMapper.readTree(it.trimIndent()) }
@@ -996,15 +883,10 @@ class InteractiveDocumentObjectBuilderTest {
@Test
fun `external block with multiple flows under display rule is built to section flow wrapped in condition flow`() {
// given
- val rule =
- aDisplayRule(Literal("C", LiteralDataType.String), Equals, Literal("C", LiteralDataType.String)).mock()
- val innerBlock = aDocObj("B_2", Block, listOf(aParagraph(aText(StringValue("Inner Text"))))).mock()
- val block = aDocObj(
- "B_1", Block, listOf(
- aDocumentObjectRef(innerBlock.id),
- aParagraph(aText(StringValue("Text"))),
- ), false, displayRuleRef = rule.id
- )
+ val rule = DisplayRuleBuilder("R_1").comparison { value("C").equals().value("C") }.build().mock()
+ val innerBlock = DocumentObjectBuilder("B_2", Block).string("Inner Text").build().mock()
+ val block = DocumentObjectBuilder("B_1", Block).documentObjectRef(innerBlock).string("Text").internal(false)
+ .displayRuleRef(rule).build()
// when
val result = subject.buildDocumentObject(block).let { xmlMapper.readTree(it.trimIndent()) }
@@ -1021,21 +903,25 @@ class InteractiveDocumentObjectBuilderTest {
sectionFlowRefs.size().shouldBeEqualTo(2)
}
- @Test
- fun `build page with multiple areas with interactive flow`() {
- val page = aDocObj(
- "P_1", Page, listOf(
- anArea(listOf(aParagraph(aText("interactive flow text 1"))), interactiveFlowName = "Logo"),
- anArea(listOf(aParagraph(aText("main flow text 1")))),
- aParagraph(aText("main flow text 2")),
- anArea(
- listOf(aParagraph(aText("interactive flow text 2"))), interactiveFlowName = "Def.InteractiveFlow1"
- ),
- anArea(listOf(aParagraph(aText("main flow text 3"))), interactiveFlowName = "Def.MainFlow"),
- anArea(listOf(aParagraph(aText("interactive flow text 3"))), interactiveFlowName = "Flow BT 1")
- )
+ @ParameterizedTest
+ @CsvSource("Page", "Template")
+ fun `build template interactive flow areas inline correctly`(contentType: DocumentObjectType) {
+ val areaContent = listOf(
+ AreaBuilder().paragraph { string("interactive flow text 1") }.interactiveFlowName("Logo").build(),
+ AreaBuilder().paragraph { string("main flow text 1") }.build(),
+ ParagraphBuilder().string("main flow text 2").build(),
+ AreaBuilder().paragraph { string("interactive flow text 2") }.interactiveFlowName("Def.InteractiveFlow1").build(),
+ AreaBuilder().paragraph { string("main flow text 3") }.interactiveFlowName("Def.MainFlow").build(),
+ AreaBuilder().paragraph { string("interactive flow text 3") }.interactiveFlowName("Flow BT 1").build()
)
+ val template = if (contentType == Page) {
+ val page = DocumentObjectBuilder("P_1", Page).content(areaContent).build().mock()
+ DocumentObjectBuilder("T_1", Template).documentObjectRef(page).build()
+ } else {
+ DocumentObjectBuilder("T_1", Template).content(areaContent).build()
+ }
+
every {
ipsService.wfd2xml(getBaseTemplateFullPath(config, null))
} returns """
@@ -1074,7 +960,7 @@ class InteractiveDocumentObjectBuilderTest {
""".trimMargin()
// when
- val result = subject.buildDocumentObject(page).let { xmlMapper.readTree(it.trimIndent()) }
+ val result = subject.buildDocumentObject(template).let { xmlMapper.readTree(it.trimIndent()) }
val mainFlow = result["Flow"].first { it["Id"].textValue() == "Def.MainFlow" }
val mainFlowContentFlowId = mainFlow["FlowContent"]["P"]["T"]["O"]["Id"].textValue()
@@ -1085,7 +971,7 @@ class InteractiveDocumentObjectBuilderTest {
mainFlowParagraphs[1]["T"][""].textValue().shouldBeEqualTo("main flow text 2")
mainFlowParagraphs[2]["T"][""].textValue().shouldBeEqualTo("main flow text 3")
result["Flow"].first { it["Id"].textValue() == mainFlowContentFlowId }["Name"].textValue()
- .shouldBeEqualTo("P_1name")
+ .shouldBeEqualTo("T_1")
val interactiveFlow = result["Flow"].first { it["Id"].textValue() == "Def.InteractiveFlow1" }
val interactiveFlowContentFlowId = interactiveFlow["FlowContent"]["P"]["T"]["O"]["Id"].textValue()
@@ -1096,88 +982,26 @@ class InteractiveDocumentObjectBuilderTest {
interactiveFlowParagraphs[1]["T"][""].textValue().shouldBeEqualTo("interactive flow text 2")
interactiveFlowParagraphs[2]["T"][""].textValue().shouldBeEqualTo("interactive flow text 3")
result["Flow"].first { it["Id"].textValue() == interactiveFlowContentFlowId }["Name"].textValue()
- .shouldBeEqualTo("P_1name_Flow BT 1")
- }
-
- @Test
- fun `build page with single area with interactive flow`(){
- val page = aDocObj(
- "P_1", Page, listOf(
- anArea(listOf(aParagraph(aText("interactive flow text 1"))), interactiveFlowName = "Logo")
- )
- )
-
- every {
- ipsService.wfd2xml(getBaseTemplateFullPath(config, null))
- } returns """
-
-
-
- 79
- Letter Content
-
-
- 80
- Flow BT 1
- {"customName":"Logo"}
-
-
-
- 80
- Normal
-
-
-
-
- """.trimMargin()
-
- // when
- val result = subject.buildDocumentObject(page).let { xmlMapper.readTree(it.trimIndent()) }
-
- val interactiveFlow = result["Flow"].first { it["Id"].textValue() == "Def.InteractiveFlow0" }
- val interactiveFlowContentFlowId = interactiveFlow["FlowContent"]["P"]["T"]["O"]["Id"].textValue()
- val interactiveFlowContentFlow = result["Flow"].last { it["Id"].textValue() == interactiveFlowContentFlowId }
- interactiveFlowContentFlow["FlowContent"]["P"]["T"][""].textValue().shouldBeEqualTo("interactive flow text 1")
- result["Flow"].first { it["Id"].textValue() == interactiveFlowContentFlowId }["Name"].textValue()
- .shouldBeEqualTo("P_1name")
+ .shouldBeEqualTo("T_1_Flow BT 1")
}
@Test
fun `first match in cell is wrapped in simple section flow`() {
// given
- val rule1 = aDisplayRule(
- Literal("A", LiteralDataType.String), Equals, Literal("A", LiteralDataType.String), id = "rule1"
- ).mock()
- val rule2 = aDisplayRule(
- Literal("B", LiteralDataType.String), Equals, Literal("B", LiteralDataType.String), id = "rule2"
- ).mock()
- val firstMatch = FirstMatch(
- cases = listOf(
- FirstMatch.Case(
- displayRuleRef = DisplayRuleRef(rule1.id),
- content = listOf(aParagraph(aText(StringValue("first case")))),
- name = "First"
- ), FirstMatch.Case(
- displayRuleRef = DisplayRuleRef(rule2.id),
- content = listOf(aParagraph(aText(StringValue("second case")))),
- name = "Second"
- )
- ), default = listOf(aParagraph(aText(StringValue("default case"))))
- )
- val block = aBlock(
- "B1", listOf(
- Table(
- rows = listOf(
- aRow(
- listOf(
- aCell(firstMatch)
- )
- )
- ), columnWidths = listOf()
- )
- )
- )
-
+ val rule1 = DisplayRuleBuilder("R_1").comparison { value("A").equals().value("A") }.build().mock()
+ val rule2 = DisplayRuleBuilder("R_2").comparison { value("B").equals().value("B") }.build().mock()
+
+ val block = DocumentObjectBuilder("B1", Block).table {
+ addRow {
+ addCell {
+ firstMatch {
+ addCase().displayRuleRef(rule1).string("first case").name("First")
+ addCase().displayRuleRef(rule2).string("second case").name("Second")
+ defaultString("default case")
+ }
+ }
+ }
+ }.build()
// when
val result = subject.buildDocumentObject(block).let { xmlMapper.readTree(it.trimIndent()) }
diff --git a/wfd-xml/api/src/main/java/com/quadient/wfdxml/api/layoutnodes/Image.java b/wfd-xml/api/src/main/java/com/quadient/wfdxml/api/layoutnodes/Image.java
index 30cb1e8..3a35bc2 100644
--- a/wfd-xml/api/src/main/java/com/quadient/wfdxml/api/layoutnodes/Image.java
+++ b/wfd-xml/api/src/main/java/com/quadient/wfdxml/api/layoutnodes/Image.java
@@ -17,6 +17,10 @@ public interface Image extends Node {
Image setResizeHeight(double height);
+ Image setUseResizeWidth(boolean useResizeWidth);
+
+ Image setUseResizeHeight(boolean useResizeHeight);
+
Image setHtmlWidthAndHeight(String htmlWidth, String htmlHeight);
Image setTransparentR(int min, int max);
diff --git a/wfd-xml/impl/src/main/java/com/quadient/wfdxml/internal/layoutnodes/ImageImpl.java b/wfd-xml/impl/src/main/java/com/quadient/wfdxml/internal/layoutnodes/ImageImpl.java
index 4e2fa27..3829dc1 100644
--- a/wfd-xml/impl/src/main/java/com/quadient/wfdxml/internal/layoutnodes/ImageImpl.java
+++ b/wfd-xml/impl/src/main/java/com/quadient/wfdxml/internal/layoutnodes/ImageImpl.java
@@ -13,8 +13,8 @@ public class ImageImpl extends NodeImpl implements Image {
private boolean useResizeHeight = false;
private boolean makeTransparent = false;
- private double resizeImageWidth = 0.0;
- private double resizeImageHeight = 0.0;
+ private Double resizeImageWidth = null;
+ private Double resizeImageHeight = null;
private double dpiX = 0.0;
private double dpiY = 0.0;
@@ -49,6 +49,7 @@ public boolean getUseResizeWidth() {
return useResizeWidth;
}
+ @Override
public ImageImpl setUseResizeWidth(boolean useResizeWidth) {
this.useResizeWidth = useResizeWidth;
return this;
@@ -58,12 +59,13 @@ public boolean getUseResizeHeight() {
return useResizeHeight;
}
+ @Override
public ImageImpl setUseResizeHeight(boolean useResizeHeight) {
this.useResizeHeight = useResizeHeight;
return this;
}
- public double getResizeImageWidth() {
+ public Double getResizeImageWidth() {
return resizeImageWidth;
}
@@ -72,7 +74,7 @@ public ImageImpl setResizeImageWidth(double resizeImageWidth) {
return this;
}
- public double getResizeImageHeight() {
+ public Double getResizeImageHeight() {
return resizeImageHeight;
}
@@ -290,11 +292,11 @@ public void export(XmlExporter exporter) {
.addElementWithStringData("ImageLocation", imageLocation)
.addElementWithDoubleData("ImageDPIX", dpiX)
.addElementWithDoubleData("ImageDPIY", dpiY)
- .addElementWithBoolData("UseResizeWidth", useResizeWidth)
- .addElementWithDoubleData("ResizeImageWidth", resizeImageWidth)
- .addElementWithBoolData("UseResizeHeight", useResizeHeight)
- .addElementWithDoubleData("ResizeImageHeight", resizeImageHeight)
- .addElementWithBoolData("MakeTransparent", makeTransparent)
+ .addElementWithBoolData("UseResizeWidth", useResizeWidth);
+ if (resizeImageWidth != null) exporter.addElementWithDoubleData("ResizeImageWidth", resizeImageWidth);
+ exporter.addElementWithBoolData("UseResizeHeight", useResizeHeight);
+ if (resizeImageHeight != null) exporter.addElementWithDoubleData("ResizeImageHeight", resizeImageHeight);
+ exporter.addElementWithBoolData("MakeTransparent", makeTransparent)
.beginElement("TransparencyR")
.addIntAttribute("X", transparencyRX)
.addIntAttribute("Y", transparencyRY)
diff --git a/wfd-xml/impl/src/test/groovy/com/quadient/wfdxml/internal/layoutnodes/ImageImplTest.groovy b/wfd-xml/impl/src/test/groovy/com/quadient/wfdxml/internal/layoutnodes/ImageImplTest.groovy
index c98cfab..2900ef9 100644
--- a/wfd-xml/impl/src/test/groovy/com/quadient/wfdxml/internal/layoutnodes/ImageImplTest.groovy
+++ b/wfd-xml/impl/src/test/groovy/com/quadient/wfdxml/internal/layoutnodes/ImageImplTest.groovy
@@ -25,9 +25,7 @@ class ImageImplTest extends Specification {
0.0
0.0
False
- 0.0
False
- 0.0
False
@@ -90,6 +88,40 @@ class ImageImplTest extends Specification {
""")
}
+ def "export image with useResizeWidth and useResizeHeight set to true but no resize values"() {
+ given:
+ ImageImpl image = new ImageImpl()
+ .setUseResizeWidth(true)
+ .setUseResizeHeight(true)
+
+ when:
+ image.export(exporter)
+
+ then:
+ assertXmlEqualsWrapRoot(exporter.buildString(), """
+ Simple
+ 0.0
+ 0.0
+ True
+ True
+ False
+
+
+
+ False
+
+
+
+ Figure
+
+
+
+ 1
+
+
+ """)
+ }
+
def "export image with ICM location"() {
given:
ImageImpl image = new ImageImpl().setImageLocation("vcs://Interactive/StandardPackage/Resources/Images/frog.png", LocationType.ICM)
@@ -104,9 +136,7 @@ class ImageImplTest extends Specification {
0.0
0.0
False
- 0.0
False
- 0.0
False
@@ -138,9 +168,7 @@ class ImageImplTest extends Specification {
0.0
0.0
False
- 0.0
False
- 0.0
False
@@ -174,9 +202,7 @@ class ImageImplTest extends Specification {
0.0
0.0
False
- 0.0
False
- 0.0
False
@@ -212,9 +238,7 @@ class ImageImplTest extends Specification {
0.0
0.0
False
- 0.0
False
- 0.0
False
diff --git a/wfd-xml/impl/src/test/resources/com/quadient/wfdxml/workflow/AllInOneUsageExample.xml b/wfd-xml/impl/src/test/resources/com/quadient/wfdxml/workflow/AllInOneUsageExample.xml
index 03da72f..dfe2e2f 100644
--- a/wfd-xml/impl/src/test/resources/com/quadient/wfdxml/workflow/AllInOneUsageExample.xml
+++ b/wfd-xml/impl/src/test/resources/com/quadient/wfdxml/workflow/AllInOneUsageExample.xml
@@ -2978,7 +2978,6 @@
0.0
0.0
False
- 0.0
True
0.024
False
diff --git a/wfd-xml/impl/src/test/resources/com/quadient/wfdxml/workflow/ImageAndLineUsageExample.xml b/wfd-xml/impl/src/test/resources/com/quadient/wfdxml/workflow/ImageAndLineUsageExample.xml
index 3e4e9b4..84f9831 100644
--- a/wfd-xml/impl/src/test/resources/com/quadient/wfdxml/workflow/ImageAndLineUsageExample.xml
+++ b/wfd-xml/impl/src/test/resources/com/quadient/wfdxml/workflow/ImageAndLineUsageExample.xml
@@ -459,7 +459,6 @@
0.0
0.0
False
- 0.0
True
0.024
False
diff --git a/wfd-xml/impl/src/test/resources/com/quadient/wfdxml/workflow/SimpleDeltaLayoutWithImage.xml b/wfd-xml/impl/src/test/resources/com/quadient/wfdxml/workflow/SimpleDeltaLayoutWithImage.xml
index 1a2a3eb..722662c 100644
--- a/wfd-xml/impl/src/test/resources/com/quadient/wfdxml/workflow/SimpleDeltaLayoutWithImage.xml
+++ b/wfd-xml/impl/src/test/resources/com/quadient/wfdxml/workflow/SimpleDeltaLayoutWithImage.xml
@@ -35,9 +35,7 @@
0.0
0.0
False
- 0.0
False
- 0.0
False