feat: Add table logic for role and permission sections

This commit is contained in:
2025-12-29 08:58:00 +01:00
parent be9d2ec9d7
commit 0490f2357e
31 changed files with 1957 additions and 390 deletions

View File

@@ -11,6 +11,7 @@ import com.betriebsratkanzlei.legalconsenthub_api.model.ApplicationFormSnapshotD
import com.betriebsratkanzlei.legalconsenthub_api.model.FormElementSectionSnapshotDto
import com.betriebsratkanzlei.legalconsenthub_api.model.FormElementSnapshotDto
import com.betriebsratkanzlei.legalconsenthub_api.model.FormElementSubSectionSnapshotDto
import com.betriebsratkanzlei.legalconsenthub_api.model.FormElementVisibilityCondition
import com.fasterxml.jackson.core.type.TypeReference
import com.fasterxml.jackson.module.kotlin.jacksonObjectMapper
import org.springframework.stereotype.Service
@@ -80,6 +81,7 @@ class ApplicationFormFormatService(
title = LatexEscaper.escape(element.title ?: ""),
description = LatexEscaper.escape(element.description ?: ""),
value = renderElementValue(element),
isTable = element.type.name == "TABLE",
)
},
)
@@ -152,8 +154,10 @@ class ApplicationFormFormatService(
val rowCount = columnData.maxOfOrNull { col -> col.size } ?: 0
if (rowCount == 0) return "Keine Daten"
val columnSpec = headers.joinToString(" | ") { "l" }
val headerRow = headers.joinToString(" & ")
// Use tabularx with Y columns (auto-wrapping) for flexible width distribution
// Y is defined as >{\raggedright\arraybackslash}X in the template
val columnSpec = headers.joinToString("") { "Y" }
val headerRow = headers.joinToString(" & ") { "\\textbf{$it}" }
val dataRows =
(0 until rowCount).map { rowIndex ->
columnData.joinToString(" & ") { col: List<String> ->
@@ -163,15 +167,15 @@ class ApplicationFormFormatService(
}
return buildString {
appendLine("\\begin{tabular}{$columnSpec}")
appendLine("\\hline")
appendLine("\\begin{tabularx}{\\textwidth}{$columnSpec}")
appendLine("\\toprule")
appendLine("$headerRow \\\\")
appendLine("\\hline")
appendLine("\\midrule")
dataRows.forEach { row: String ->
appendLine("$row \\\\")
}
appendLine("\\hline")
appendLine("\\end{tabular}")
appendLine("\\bottomrule")
appendLine("\\end{tabularx}")
}
}
@@ -213,8 +217,17 @@ class ApplicationFormFormatService(
element: FormElementSnapshotDto,
formElementsByRef: Map<String, FormElementSnapshotDto>,
): Boolean {
val condition = element.visibilityCondition ?: return true
val conditions = element.visibilityConditions
if (conditions.isNullOrEmpty()) return true
// All conditions must be met (AND logic)
return conditions.all { condition -> evaluateSingleCondition(condition, formElementsByRef) }
}
private fun evaluateSingleCondition(
condition: FormElementVisibilityCondition,
formElementsByRef: Map<String, FormElementSnapshotDto>,
): Boolean {
val sourceElement = formElementsByRef[condition.sourceFormElementReference] ?: return false
val sourceValue = getFormElementValue(sourceElement)

View File

@@ -3,7 +3,10 @@ package com.betriebsratkanzlei.legalconsenthub.application_form.export.latex
object LatexEscaper {
fun escape(text: String?): String {
if (text == null) return ""
return text
// First decode common HTML entities that may be present in user input
val decoded = decodeHtmlEntities(text)
// Then escape for LaTeX
return decoded
.replace("\\", "\\textbackslash{}")
.replace("{", "\\{")
.replace("}", "\\}")
@@ -16,4 +19,14 @@ object LatexEscaper {
.replace("~", "\\textasciitilde{}")
.replace("\n", "\\\\")
}
private fun decodeHtmlEntities(text: String): String =
text
.replace("&amp;", "&")
.replace("&lt;", "<")
.replace("&gt;", ">")
.replace("&quot;", "\"")
.replace("&#39;", "'")
.replace("&apos;", "'")
.replace("&nbsp;", " ")
}

View File

@@ -28,4 +28,5 @@ data class LatexFormElement(
val title: String,
val description: String?,
val value: String,
val isTable: Boolean = false,
)

View File

@@ -8,14 +8,14 @@ import com.betriebsratkanzlei.legalconsenthub.form_element.FormElement
import com.betriebsratkanzlei.legalconsenthub.form_element.FormElementSection
import com.betriebsratkanzlei.legalconsenthub.form_element.FormElementSubSection
import com.betriebsratkanzlei.legalconsenthub.form_element.FormElementVisibilityConditionMapper
import com.betriebsratkanzlei.legalconsenthub.form_element.FormOption
import com.betriebsratkanzlei.legalconsenthub.form_element.FormOptionMapper
import com.betriebsratkanzlei.legalconsenthub.form_element.SectionSpawnTriggerMapper
import com.betriebsratkanzlei.legalconsenthub.form_element.TableRowPresetMapper
import com.betriebsratkanzlei.legalconsenthub.user.User
import com.betriebsratkanzlei.legalconsenthub_api.model.ApplicationFormSnapshotDto
import com.betriebsratkanzlei.legalconsenthub_api.model.FormElementSectionSnapshotDto
import com.betriebsratkanzlei.legalconsenthub_api.model.FormElementSnapshotDto
import com.betriebsratkanzlei.legalconsenthub_api.model.FormElementSubSectionSnapshotDto
import com.betriebsratkanzlei.legalconsenthub_api.model.FormOptionDto
import com.fasterxml.jackson.databind.ObjectMapper
import org.springframework.stereotype.Service
import org.springframework.transaction.annotation.Transactional
@@ -28,6 +28,8 @@ class ApplicationFormVersionService(
private val objectMapper: ObjectMapper,
private val spawnTriggerMapper: SectionSpawnTriggerMapper,
private val visibilityConditionMapper: FormElementVisibilityConditionMapper,
private val tableRowPresetMapper: TableRowPresetMapper,
private val formOptionMapper: FormOptionMapper,
) {
@Transactional
fun createVersion(
@@ -123,26 +125,22 @@ class ApplicationFormVersionService(
title = element.title,
description = element.description,
type = element.type,
options =
element.options.map { option ->
FormOptionDto(
value = option.value,
label = option.label,
processingPurpose = option.processingPurpose,
employeeDataCategory = option.employeeDataCategory,
)
},
visibilityCondition =
element.visibilityCondition?.let {
visibilityConditionMapper.toFormElementVisibilityConditionDto(
it,
)
},
sectionSpawnTrigger =
element.sectionSpawnTrigger?.let {
options = element.options.map { formOptionMapper.toFormOptionDto(it) },
visibilityConditions =
element.visibilityConditions
.map {
visibilityConditionMapper
.toFormElementVisibilityConditionDto(it)
},
sectionSpawnTriggers =
element.sectionSpawnTriggers.map {
spawnTriggerMapper.toSectionSpawnTriggerDto(it)
},
isClonable = element.isClonable,
tableRowPreset =
element.tableRowPreset?.let {
tableRowPresetMapper.toTableRowPresetDto(it)
},
)
},
)
@@ -185,23 +183,23 @@ class ApplicationFormVersionService(
formElementSubSection = subsection,
options =
elementSnapshot.options
.map { optionDto ->
FormOption(
value = optionDto.value,
label = optionDto.label,
processingPurpose = optionDto.processingPurpose,
employeeDataCategory = optionDto.employeeDataCategory,
)
}.toMutableList(),
visibilityCondition =
elementSnapshot.visibilityCondition?.let {
visibilityConditionMapper.toFormElementVisibilityCondition(it)
},
sectionSpawnTrigger =
elementSnapshot.sectionSpawnTrigger?.let {
spawnTriggerMapper.toSectionSpawnTrigger(it)
},
.map { formOptionMapper.toFormOption(it) }
.toMutableList(),
visibilityConditions =
elementSnapshot.visibilityConditions
?.map { visibilityConditionMapper.toFormElementVisibilityCondition(it) }
?.toMutableList()
?: mutableListOf(),
sectionSpawnTriggers =
elementSnapshot.sectionSpawnTriggers
?.map { spawnTriggerMapper.toSectionSpawnTrigger(it) }
?.toMutableList()
?: mutableListOf(),
isClonable = elementSnapshot.isClonable ?: false,
tableRowPreset =
elementSnapshot.tableRowPreset?.let {
tableRowPresetMapper.toTableRowPreset(it)
},
)
subsection.formElements.add(element)
}

View File

@@ -1,6 +1,8 @@
package com.betriebsratkanzlei.legalconsenthub.form_element
import com.betriebsratkanzlei.legalconsenthub_api.model.FormElementType
import jakarta.persistence.AttributeOverride
import jakarta.persistence.AttributeOverrides
import jakarta.persistence.CollectionTable
import jakarta.persistence.Column
import jakarta.persistence.ElementCollection
@@ -28,9 +30,25 @@ class FormElement(
@ManyToOne
@JoinColumn(name = "form_element_sub_section_id", nullable = false)
var formElementSubSection: FormElementSubSection? = null,
@Embedded
var visibilityCondition: FormElementVisibilityCondition? = null,
@Embedded
var sectionSpawnTrigger: SectionSpawnTrigger? = null,
@ElementCollection
@CollectionTable(name = "visibility_conditions", joinColumns = [JoinColumn(name = "form_element_id")])
var visibilityConditions: MutableList<FormElementVisibilityCondition> = mutableListOf(),
@ElementCollection
@CollectionTable(name = "section_spawn_triggers", joinColumns = [JoinColumn(name = "form_element_id")])
var sectionSpawnTriggers: MutableList<SectionSpawnTrigger> = mutableListOf(),
var isClonable: Boolean = false,
@Embedded
@AttributeOverrides(
AttributeOverride(name = "sourceTableReference", column = Column(name = "row_preset_source_table_ref")),
AttributeOverride(
name = "filterCondition.sourceColumnIndex",
column = Column(name = "row_preset_filter_src_col_idx"),
),
AttributeOverride(
name = "filterCondition.expectedValue",
column = Column(name = "row_preset_filter_expected_val"),
),
AttributeOverride(name = "filterCondition.operator", column = Column(name = "row_preset_filter_operator")),
)
var tableRowPreset: TableRowPreset? = null,
)

View File

@@ -8,6 +8,7 @@ class FormElementMapper(
private val formOptionMapper: FormOptionMapper,
private val visibilityConditionMapper: FormElementVisibilityConditionMapper,
private val spawnTriggerMapper: SectionSpawnTriggerMapper,
private val tableRowPresetMapper: TableRowPresetMapper,
) {
fun toFormElementDto(formElement: FormElement): FormElementDto =
FormElementDto(
@@ -20,15 +21,19 @@ class FormElementMapper(
formElementSubSectionId =
formElement.formElementSubSection?.id
?: throw IllegalStateException("FormElementSubSection ID must not be null!"),
visibilityCondition =
formElement.visibilityCondition?.let {
visibilityConditions =
formElement.visibilityConditions.map {
visibilityConditionMapper.toFormElementVisibilityConditionDto(it)
},
sectionSpawnTrigger =
formElement.sectionSpawnTrigger?.let {
sectionSpawnTriggers =
formElement.sectionSpawnTriggers.map {
spawnTriggerMapper.toSectionSpawnTriggerDto(it)
},
isClonable = formElement.isClonable,
tableRowPreset =
formElement.tableRowPreset?.let {
tableRowPresetMapper.toTableRowPresetDto(it)
},
)
fun toFormElement(
@@ -43,15 +48,21 @@ class FormElementMapper(
options = formElement.options.map { formOptionMapper.toFormOption(it) }.toMutableList(),
type = formElement.type,
formElementSubSection = formElementSubSection,
visibilityCondition =
formElement.visibilityCondition?.let {
visibilityConditionMapper.toFormElementVisibilityCondition(it)
},
sectionSpawnTrigger =
formElement.sectionSpawnTrigger?.let {
spawnTriggerMapper.toSectionSpawnTrigger(it)
},
visibilityConditions =
formElement.visibilityConditions
?.map { visibilityConditionMapper.toFormElementVisibilityCondition(it) }
?.toMutableList()
?: mutableListOf(),
sectionSpawnTriggers =
formElement.sectionSpawnTriggers
?.map { spawnTriggerMapper.toSectionSpawnTrigger(it) }
?.toMutableList()
?: mutableListOf(),
isClonable = formElement.isClonable ?: false,
tableRowPreset =
formElement.tableRowPreset?.let {
tableRowPresetMapper.toTableRowPreset(it)
},
)
fun toNewFormElement(
@@ -66,14 +77,20 @@ class FormElementMapper(
options = formElement.options.map { formOptionMapper.toFormOption(it) }.toMutableList(),
type = formElement.type,
formElementSubSection = formElementSubSection,
visibilityCondition =
formElement.visibilityCondition?.let {
visibilityConditionMapper.toFormElementVisibilityCondition(it)
},
sectionSpawnTrigger =
formElement.sectionSpawnTrigger?.let {
spawnTriggerMapper.toSectionSpawnTrigger(it)
},
visibilityConditions =
formElement.visibilityConditions
?.map { visibilityConditionMapper.toFormElementVisibilityCondition(it) }
?.toMutableList()
?: mutableListOf(),
sectionSpawnTriggers =
formElement.sectionSpawnTriggers
?.map { spawnTriggerMapper.toSectionSpawnTrigger(it) }
?.toMutableList()
?: mutableListOf(),
isClonable = formElement.isClonable ?: false,
tableRowPreset =
formElement.tableRowPreset?.let {
tableRowPresetMapper.toTableRowPreset(it)
},
)
}

View File

@@ -2,8 +2,11 @@ package com.betriebsratkanzlei.legalconsenthub.form_element
import com.betriebsratkanzlei.legalconsenthub_api.model.EmployeeDataCategory
import com.betriebsratkanzlei.legalconsenthub_api.model.ProcessingPurpose
import jakarta.persistence.AttributeOverride
import jakarta.persistence.AttributeOverrides
import jakarta.persistence.Column
import jakarta.persistence.Embeddable
import jakarta.persistence.Embedded
@Embeddable
class FormOption(
@@ -15,4 +18,21 @@ class FormOption(
var processingPurpose: ProcessingPurpose,
@Column(nullable = false)
var employeeDataCategory: EmployeeDataCategory,
@Embedded
@AttributeOverrides(
AttributeOverride(name = "sourceTableReference", column = Column(name = "col_config_source_table_ref")),
AttributeOverride(name = "sourceColumnIndex", column = Column(name = "col_config_source_col_idx")),
AttributeOverride(
name = "filterCondition.sourceColumnIndex",
column = Column(name = "col_config_filter_src_col_idx"),
),
AttributeOverride(
name = "filterCondition.expectedValue",
column = Column(name = "col_config_filter_expected_val"),
),
AttributeOverride(name = "filterCondition.operator", column = Column(name = "col_config_filter_operator")),
AttributeOverride(name = "isReadOnly", column = Column(name = "col_config_is_read_only")),
AttributeOverride(name = "isCheckbox", column = Column(name = "col_config_is_checkbox")),
)
var columnConfig: TableColumnConfig? = null,
)

View File

@@ -4,13 +4,16 @@ import com.betriebsratkanzlei.legalconsenthub_api.model.FormOptionDto
import org.springframework.stereotype.Component
@Component
class FormOptionMapper {
class FormOptionMapper(
private val columnConfigMapper: TableColumnConfigMapper,
) {
fun toFormOptionDto(formOption: FormOption): FormOptionDto =
FormOptionDto(
value = formOption.value,
label = formOption.label,
processingPurpose = formOption.processingPurpose,
employeeDataCategory = formOption.employeeDataCategory,
columnConfig = formOption.columnConfig?.let { columnConfigMapper.toTableColumnConfigDto(it) },
)
fun toFormOption(formOptionDto: FormOptionDto): FormOption =
@@ -19,5 +22,6 @@ class FormOptionMapper {
label = formOptionDto.label,
processingPurpose = formOptionDto.processingPurpose,
employeeDataCategory = formOptionDto.employeeDataCategory,
columnConfig = formOptionDto.columnConfig?.let { columnConfigMapper.toTableColumnConfig(it) },
)
}

View File

@@ -0,0 +1,32 @@
package com.betriebsratkanzlei.legalconsenthub.form_element
import jakarta.persistence.AttributeOverride
import jakarta.persistence.AttributeOverrides
import jakarta.persistence.Column
import jakarta.persistence.Embeddable
import jakarta.persistence.Embedded
@Embeddable
data class TableColumnConfig(
val sourceTableReference: String? = null,
val sourceColumnIndex: Int? = null,
@Embedded
val filterCondition: TableColumnFilter? = null,
@Embedded
@AttributeOverrides(
AttributeOverride(name = "constraintTableReference", column = Column(name = "row_constraint_table_reference")),
AttributeOverride(name = "constraintKeyColumnIndex", column = Column(name = "row_constraint_key_column_index")),
AttributeOverride(
name = "constraintValueColumnIndex",
column = Column(name = "row_constraint_value_column_index"),
),
AttributeOverride(
name = "currentRowKeyColumnIndex",
column = Column(name = "row_constraint_current_row_key_column_index"),
),
)
val rowConstraint: TableRowConstraint? = null,
val isReadOnly: Boolean = false,
val isMultipleAllowed: Boolean = false,
val isCheckbox: Boolean = false,
)

View File

@@ -0,0 +1,32 @@
package com.betriebsratkanzlei.legalconsenthub.form_element
import com.betriebsratkanzlei.legalconsenthub_api.model.TableColumnConfigDto
import org.springframework.stereotype.Component
@Component
class TableColumnConfigMapper(
private val filterMapper: TableColumnFilterMapper,
private val rowConstraintMapper: TableRowConstraintMapper,
) {
fun toTableColumnConfigDto(config: TableColumnConfig): TableColumnConfigDto =
TableColumnConfigDto(
sourceTableReference = config.sourceTableReference,
sourceColumnIndex = config.sourceColumnIndex,
filterCondition = config.filterCondition?.let { filterMapper.toTableColumnFilterDto(it) },
rowConstraint = config.rowConstraint?.let { rowConstraintMapper.toTableRowConstraintDto(it) },
isReadOnly = config.isReadOnly,
isMultipleAllowed = config.isMultipleAllowed,
isCheckbox = config.isCheckbox,
)
fun toTableColumnConfig(dto: TableColumnConfigDto): TableColumnConfig =
TableColumnConfig(
sourceTableReference = dto.sourceTableReference,
sourceColumnIndex = dto.sourceColumnIndex,
filterCondition = dto.filterCondition?.let { filterMapper.toTableColumnFilter(it) },
rowConstraint = dto.rowConstraint?.let { rowConstraintMapper.toTableRowConstraint(it) },
isReadOnly = dto.isReadOnly ?: false,
isMultipleAllowed = dto.isMultipleAllowed ?: false,
isCheckbox = dto.isCheckbox ?: false,
)
}

View File

@@ -0,0 +1,13 @@
package com.betriebsratkanzlei.legalconsenthub.form_element
import jakarta.persistence.Embeddable
import jakarta.persistence.EnumType
import jakarta.persistence.Enumerated
@Embeddable
data class TableColumnFilter(
val sourceColumnIndex: Int? = null,
val expectedValue: String? = null,
@Enumerated(EnumType.STRING)
val operator: VisibilityConditionOperator = VisibilityConditionOperator.EQUALS,
)

View File

@@ -0,0 +1,38 @@
package com.betriebsratkanzlei.legalconsenthub.form_element
import com.betriebsratkanzlei.legalconsenthub_api.model.TableColumnFilterDto
import org.springframework.stereotype.Component
import com.betriebsratkanzlei.legalconsenthub_api.model.VisibilityConditionOperator as VisibilityConditionOperatorDto
@Component
class TableColumnFilterMapper {
fun toTableColumnFilterDto(filter: TableColumnFilter): TableColumnFilterDto =
TableColumnFilterDto(
sourceColumnIndex = filter.sourceColumnIndex,
expectedValue = filter.expectedValue,
operator = filter.operator.toDto(),
)
fun toTableColumnFilter(dto: TableColumnFilterDto): TableColumnFilter =
TableColumnFilter(
sourceColumnIndex = dto.sourceColumnIndex,
expectedValue = dto.expectedValue,
operator = dto.operator?.toEntity() ?: VisibilityConditionOperator.EQUALS,
)
private fun VisibilityConditionOperator.toDto(): VisibilityConditionOperatorDto =
when (this) {
VisibilityConditionOperator.EQUALS -> VisibilityConditionOperatorDto.EQUALS
VisibilityConditionOperator.NOT_EQUALS -> VisibilityConditionOperatorDto.NOT_EQUALS
VisibilityConditionOperator.IS_EMPTY -> VisibilityConditionOperatorDto.IS_EMPTY
VisibilityConditionOperator.IS_NOT_EMPTY -> VisibilityConditionOperatorDto.IS_NOT_EMPTY
}
private fun VisibilityConditionOperatorDto.toEntity(): VisibilityConditionOperator =
when (this) {
VisibilityConditionOperatorDto.EQUALS -> VisibilityConditionOperator.EQUALS
VisibilityConditionOperatorDto.NOT_EQUALS -> VisibilityConditionOperator.NOT_EQUALS
VisibilityConditionOperatorDto.IS_EMPTY -> VisibilityConditionOperator.IS_EMPTY
VisibilityConditionOperatorDto.IS_NOT_EMPTY -> VisibilityConditionOperator.IS_NOT_EMPTY
}
}

View File

@@ -0,0 +1,9 @@
package com.betriebsratkanzlei.legalconsenthub.form_element
import jakarta.persistence.Embeddable
@Embeddable
data class TableColumnMapping(
val sourceColumnIndex: Int,
val targetColumnIndex: Int,
)

View File

@@ -0,0 +1,19 @@
package com.betriebsratkanzlei.legalconsenthub.form_element
import com.betriebsratkanzlei.legalconsenthub_api.model.TableColumnMappingDto
import org.springframework.stereotype.Component
@Component
class TableColumnMappingMapper {
fun toTableColumnMappingDto(mapping: TableColumnMapping): TableColumnMappingDto =
TableColumnMappingDto(
sourceColumnIndex = mapping.sourceColumnIndex,
targetColumnIndex = mapping.targetColumnIndex,
)
fun toTableColumnMapping(dto: TableColumnMappingDto): TableColumnMapping =
TableColumnMapping(
sourceColumnIndex = dto.sourceColumnIndex ?: 0,
targetColumnIndex = dto.targetColumnIndex ?: 0,
)
}

View File

@@ -0,0 +1,11 @@
package com.betriebsratkanzlei.legalconsenthub.form_element
import jakarta.persistence.Embeddable
@Embeddable
data class TableRowConstraint(
val constraintTableReference: String? = null,
val constraintKeyColumnIndex: Int? = null,
val constraintValueColumnIndex: Int? = null,
val currentRowKeyColumnIndex: Int? = null,
)

View File

@@ -0,0 +1,23 @@
package com.betriebsratkanzlei.legalconsenthub.form_element
import com.betriebsratkanzlei.legalconsenthub_api.model.TableRowConstraintDto
import org.springframework.stereotype.Component
@Component
class TableRowConstraintMapper {
fun toTableRowConstraintDto(constraint: TableRowConstraint): TableRowConstraintDto =
TableRowConstraintDto(
constraintTableReference = constraint.constraintTableReference,
constraintKeyColumnIndex = constraint.constraintKeyColumnIndex,
constraintValueColumnIndex = constraint.constraintValueColumnIndex,
currentRowKeyColumnIndex = constraint.currentRowKeyColumnIndex,
)
fun toTableRowConstraint(dto: TableRowConstraintDto): TableRowConstraint =
TableRowConstraint(
constraintTableReference = dto.constraintTableReference,
constraintKeyColumnIndex = dto.constraintKeyColumnIndex,
constraintValueColumnIndex = dto.constraintValueColumnIndex,
currentRowKeyColumnIndex = dto.currentRowKeyColumnIndex,
)
}

View File

@@ -0,0 +1,18 @@
package com.betriebsratkanzlei.legalconsenthub.form_element
import jakarta.persistence.CollectionTable
import jakarta.persistence.ElementCollection
import jakarta.persistence.Embeddable
import jakarta.persistence.Embedded
import jakarta.persistence.JoinColumn
@Embeddable
data class TableRowPreset(
val sourceTableReference: String? = null,
@Embedded
val filterCondition: TableColumnFilter? = null,
@ElementCollection
@CollectionTable(name = "table_column_mappings", joinColumns = [JoinColumn(name = "form_element_id")])
val columnMappings: MutableList<TableColumnMapping> = mutableListOf(),
val canAddRows: Boolean? = null,
)

View File

@@ -0,0 +1,27 @@
package com.betriebsratkanzlei.legalconsenthub.form_element
import com.betriebsratkanzlei.legalconsenthub_api.model.TableRowPresetDto
import org.springframework.stereotype.Component
@Component
class TableRowPresetMapper(
private val filterMapper: TableColumnFilterMapper,
private val mappingMapper: TableColumnMappingMapper,
) {
fun toTableRowPresetDto(preset: TableRowPreset): TableRowPresetDto =
TableRowPresetDto(
sourceTableReference = preset.sourceTableReference,
filterCondition = preset.filterCondition?.let { filterMapper.toTableColumnFilterDto(it) },
columnMappings = preset.columnMappings.map { mappingMapper.toTableColumnMappingDto(it) },
canAddRows = preset.canAddRows ?: true,
)
fun toTableRowPreset(dto: TableRowPresetDto): TableRowPreset =
TableRowPreset(
sourceTableReference = dto.sourceTableReference,
filterCondition = dto.filterCondition?.let { filterMapper.toTableColumnFilter(it) },
columnMappings =
dto.columnMappings?.map { mappingMapper.toTableColumnMapping(it) }?.toMutableList() ?: mutableListOf(),
canAddRows = dto.canAddRows,
)
}

View File

@@ -53,33 +53,43 @@ create table comment
create table form_element_options
(
employee_data_category smallint not null check (employee_data_category between 0 and 3),
processing_purpose smallint not null check (processing_purpose between 0 and 3),
form_element_id uuid not null,
label varchar(255) not null,
option_value TEXT not null
col_config_filter_src_col_idx integer,
col_config_is_checkbox boolean,
col_config_is_read_only boolean,
col_config_source_col_idx integer,
employee_data_category smallint not null check (employee_data_category between 0 and 3),
is_multiple_allowed boolean,
processing_purpose smallint not null check (processing_purpose between 0 and 3),
row_constraint_current_row_key_column_index integer,
row_constraint_key_column_index integer,
row_constraint_value_column_index integer,
form_element_id uuid not null,
col_config_filter_expected_val varchar(255),
col_config_filter_operator varchar(255) check (col_config_filter_operator in
('EQUALS', 'NOT_EQUALS', 'IS_EMPTY',
'IS_NOT_EMPTY')),
col_config_source_table_ref varchar(255),
label varchar(255) not null,
option_value TEXT not null,
row_constraint_table_reference varchar(255)
);
create table form_element
(
form_element_order integer,
is_clonable boolean not null,
type smallint not null check (type between 0 and 7),
form_element_sub_section_id uuid not null,
id uuid not null,
description varchar(255),
form_element_condition_type varchar(255) check (form_element_condition_type in ('SHOW', 'HIDE')),
form_element_expected_value varchar(255),
form_element_operator varchar(255) check (form_element_operator in
('EQUALS', 'NOT_EQUALS', 'IS_EMPTY', 'IS_NOT_EMPTY')),
reference varchar(255),
section_spawn_condition_type varchar(255) check (section_spawn_condition_type in ('SHOW', 'HIDE')),
section_spawn_expected_value varchar(255),
section_spawn_operator varchar(255) check (section_spawn_operator in
('EQUALS', 'NOT_EQUALS', 'IS_EMPTY', 'IS_NOT_EMPTY')),
source_form_element_reference varchar(255),
template_reference varchar(255),
title varchar(255),
can_add_rows boolean,
form_element_order integer,
is_clonable boolean not null,
row_preset_filter_src_col_idx integer,
type smallint not null check (type between 0 and 8),
form_element_sub_section_id uuid not null,
id uuid not null,
description varchar(255),
reference varchar(255),
row_preset_filter_expected_val varchar(255),
row_preset_filter_operator varchar(255) check (row_preset_filter_operator in
('EQUALS', 'NOT_EQUALS', 'IS_EMPTY', 'IS_NOT_EMPTY')),
row_preset_source_table_ref varchar(255),
title varchar(255),
primary key (id)
);
@@ -122,6 +132,33 @@ create table notification
primary key (id)
);
create table section_spawn_triggers
(
form_element_id uuid not null,
section_spawn_condition_type varchar(255) check (section_spawn_condition_type in ('SHOW', 'HIDE')),
section_spawn_expected_value varchar(255),
section_spawn_operator varchar(255) check (section_spawn_operator in
('EQUALS', 'NOT_EQUALS', 'IS_EMPTY', 'IS_NOT_EMPTY')),
template_reference varchar(255)
);
create table table_column_mappings
(
source_column_index integer,
target_column_index integer,
form_element_id uuid not null
);
create table visibility_conditions
(
form_element_id uuid not null,
form_element_condition_type varchar(255) check (form_element_condition_type in ('SHOW', 'HIDE')),
form_element_expected_value varchar(255),
form_element_operator varchar(255) check (form_element_operator in
('EQUALS', 'NOT_EQUALS', 'IS_EMPTY', 'IS_NOT_EMPTY')),
source_form_element_reference varchar(255)
);
alter table if exists application_form
add constraint FKhtad5onoy2jknhtyfmx6cvvey
foreign key (created_by_id)
@@ -182,3 +219,18 @@ alter table if exists notification
add constraint FKeg1j4hnp0y4lbm0y35hgr4e8r
foreign key (recipient_id)
references app_user;
alter table if exists section_spawn_triggers
add constraint FK7lf0hf8cepm2o9nty147x2ahm
foreign key (form_element_id)
references form_element;
alter table if exists table_column_mappings
add constraint FK2t3a4fl5kqtqky39r7boqegf9
foreign key (form_element_id)
references form_element;
alter table if exists visibility_conditions
add constraint FK5xuf7bd179ogpq5a1m3g8q7jb
foreign key (form_element_id)
references form_element;

View File

@@ -15,6 +15,12 @@
\usepackage{xcolor}
\usepackage{tcolorbox}
\usepackage[normalem]{ulem}
\usepackage{tabularx}
\usepackage{array}
\usepackage{booktabs}
% Define column type for auto-wrapping text
\newcolumntype{Y}{>{\raggedright\arraybackslash}X}
\hypersetup{
colorlinks=true,
@@ -73,12 +79,22 @@ Dieses Dokument enthält die Details der Betriebsvereinbarung "[[${applicationFo
\textit{\small [[${element.description}]]}
[/]
[# th:if="${element.isTable}"]
\vspace{0.5em}
\noindent
\small
[(${element.value})]
\normalsize
\vspace{0.5em}
[/]
[# th:if="${!element.isTable}"]
\begin{tcolorbox}[colback=gray!5, colframe=gray!20, arc=0mm, boxrule=0.5pt]
[[${element.value}]]
\end{tcolorbox}
[/]
[/]
[/]
[/]
\vspace{3cm}