feat: Cleanup old HTML and non-versioned PDF export
This commit is contained in:
@@ -170,35 +170,6 @@ paths:
|
|||||||
"503":
|
"503":
|
||||||
$ref: "https://api.swaggerhub.com/domains/smartbear-public/ProblemDetails/1.0.0#/components/responses/ServiceUnavailable"
|
$ref: "https://api.swaggerhub.com/domains/smartbear-public/ProblemDetails/1.0.0#/components/responses/ServiceUnavailable"
|
||||||
|
|
||||||
/application-forms/{id}/html:
|
|
||||||
get:
|
|
||||||
summary: Returns the application form rendered as HTML
|
|
||||||
operationId: getApplicationFormHtml
|
|
||||||
tags:
|
|
||||||
- application-form
|
|
||||||
parameters:
|
|
||||||
- name: id
|
|
||||||
in: path
|
|
||||||
required: true
|
|
||||||
schema:
|
|
||||||
type: string
|
|
||||||
format: uuid
|
|
||||||
responses:
|
|
||||||
'200':
|
|
||||||
description: Application form as HTML
|
|
||||||
content:
|
|
||||||
text/html:
|
|
||||||
schema:
|
|
||||||
type: string
|
|
||||||
"400":
|
|
||||||
$ref: "https://api.swaggerhub.com/domains/smartbear-public/ProblemDetails/1.0.0#/components/responses/BadRequest"
|
|
||||||
"401":
|
|
||||||
$ref: "https://api.swaggerhub.com/domains/smartbear-public/ProblemDetails/1.0.0#/components/responses/Unauthorized"
|
|
||||||
"500":
|
|
||||||
$ref: "https://api.swaggerhub.com/domains/smartbear-public/ProblemDetails/1.0.0#/components/responses/ServerError"
|
|
||||||
"503":
|
|
||||||
$ref: "https://api.swaggerhub.com/domains/smartbear-public/ProblemDetails/1.0.0#/components/responses/ServiceUnavailable"
|
|
||||||
|
|
||||||
/application-forms/{id}/submit:
|
/application-forms/{id}/submit:
|
||||||
post:
|
post:
|
||||||
summary: Submit an application form
|
summary: Submit an application form
|
||||||
|
|||||||
@@ -51,16 +51,6 @@ class ApplicationFormController(
|
|||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
|
||||||
@PreAuthorize(
|
|
||||||
"hasAnyRole('CHIEF_EXECUTIVE_OFFICER', 'BUSINESS_DEPARTMENT', 'IT_DEPARTMENT', 'HUMAN_RESOURCES', 'HEAD_OF_WORKS_COUNCIL', 'WORKS_COUNCIL', 'EMPLOYEE')",
|
|
||||||
)
|
|
||||||
override fun getApplicationFormHtml(id: UUID): ResponseEntity<String> {
|
|
||||||
val applicationForm = applicationFormService.getApplicationFormById(id)
|
|
||||||
return ResponseEntity.ok(
|
|
||||||
applicationFormFormatService.generateHtml(applicationForm),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
@PreAuthorize(
|
@PreAuthorize(
|
||||||
"hasAnyRole('CHIEF_EXECUTIVE_OFFICER', 'BUSINESS_DEPARTMENT', 'IT_DEPARTMENT', 'HUMAN_RESOURCES', 'HEAD_OF_WORKS_COUNCIL', 'WORKS_COUNCIL')",
|
"hasAnyRole('CHIEF_EXECUTIVE_OFFICER', 'BUSINESS_DEPARTMENT', 'IT_DEPARTMENT', 'HUMAN_RESOURCES', 'HEAD_OF_WORKS_COUNCIL', 'WORKS_COUNCIL')",
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -7,11 +7,6 @@ import com.betriebsratkanzlei.legalconsenthub.application_form.export.latex.Late
|
|||||||
import com.betriebsratkanzlei.legalconsenthub.application_form.export.latex.LatexSection
|
import com.betriebsratkanzlei.legalconsenthub.application_form.export.latex.LatexSection
|
||||||
import com.betriebsratkanzlei.legalconsenthub.application_form.export.latex.LatexSubSection
|
import com.betriebsratkanzlei.legalconsenthub.application_form.export.latex.LatexSubSection
|
||||||
import com.betriebsratkanzlei.legalconsenthub.application_form.export.latex.RichTextToLatexConverter
|
import com.betriebsratkanzlei.legalconsenthub.application_form.export.latex.RichTextToLatexConverter
|
||||||
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.VisibilityConditionOperator
|
|
||||||
import com.betriebsratkanzlei.legalconsenthub.form_element.VisibilityConditionType
|
|
||||||
import com.betriebsratkanzlei.legalconsenthub_api.model.ApplicationFormSnapshotDto
|
import com.betriebsratkanzlei.legalconsenthub_api.model.ApplicationFormSnapshotDto
|
||||||
import com.betriebsratkanzlei.legalconsenthub_api.model.FormElementSectionSnapshotDto
|
import com.betriebsratkanzlei.legalconsenthub_api.model.FormElementSectionSnapshotDto
|
||||||
import com.betriebsratkanzlei.legalconsenthub_api.model.FormElementSnapshotDto
|
import com.betriebsratkanzlei.legalconsenthub_api.model.FormElementSnapshotDto
|
||||||
@@ -23,7 +18,6 @@ import java.time.Instant
|
|||||||
import java.time.LocalDate
|
import java.time.LocalDate
|
||||||
import java.time.ZoneId
|
import java.time.ZoneId
|
||||||
import java.time.format.DateTimeFormatter
|
import java.time.format.DateTimeFormatter
|
||||||
import java.util.UUID
|
|
||||||
import com.betriebsratkanzlei.legalconsenthub_api.model.VisibilityConditionOperator as VisibilityConditionOperatorDto
|
import com.betriebsratkanzlei.legalconsenthub_api.model.VisibilityConditionOperator as VisibilityConditionOperatorDto
|
||||||
import com.betriebsratkanzlei.legalconsenthub_api.model.VisibilityConditionType as VisibilityConditionTypeDto
|
import com.betriebsratkanzlei.legalconsenthub_api.model.VisibilityConditionType as VisibilityConditionTypeDto
|
||||||
|
|
||||||
@@ -33,11 +27,6 @@ class ApplicationFormFormatService(
|
|||||||
private val richTextToLatexConverter: RichTextToLatexConverter,
|
private val richTextToLatexConverter: RichTextToLatexConverter,
|
||||||
private val pdfRenderer: LatexPdfRenderer,
|
private val pdfRenderer: LatexPdfRenderer,
|
||||||
) {
|
) {
|
||||||
fun generatePdf(applicationForm: ApplicationForm): ByteArray {
|
|
||||||
val latexContent = generateLatex(applicationForm)
|
|
||||||
return pdfRenderer.render(latexContent)
|
|
||||||
}
|
|
||||||
|
|
||||||
fun generatePdf(
|
fun generatePdf(
|
||||||
snapshot: ApplicationFormSnapshotDto,
|
snapshot: ApplicationFormSnapshotDto,
|
||||||
createdAt: Instant?,
|
createdAt: Instant?,
|
||||||
@@ -46,17 +35,6 @@ class ApplicationFormFormatService(
|
|||||||
return pdfRenderer.render(latexContent)
|
return pdfRenderer.render(latexContent)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun generateLatex(applicationForm: ApplicationForm): String {
|
|
||||||
val filteredForm = filterVisibleElements(applicationForm)
|
|
||||||
val exportModel = buildLatexExportModel(filteredForm)
|
|
||||||
|
|
||||||
val context =
|
|
||||||
Context().apply {
|
|
||||||
setVariable("applicationForm", exportModel)
|
|
||||||
}
|
|
||||||
return templateEngine.process("application_form_latex_template", context)
|
|
||||||
}
|
|
||||||
|
|
||||||
fun generateLatex(
|
fun generateLatex(
|
||||||
snapshot: ApplicationFormSnapshotDto,
|
snapshot: ApplicationFormSnapshotDto,
|
||||||
createdAt: Instant?,
|
createdAt: Instant?,
|
||||||
@@ -71,50 +49,6 @@ class ApplicationFormFormatService(
|
|||||||
return templateEngine.process("application_form_latex_template", context)
|
return templateEngine.process("application_form_latex_template", context)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun generateHtml(applicationForm: ApplicationForm): String {
|
|
||||||
val filteredForm = filterVisibleElements(applicationForm)
|
|
||||||
val context =
|
|
||||||
Context().apply {
|
|
||||||
setVariable("applicationForm", filteredForm)
|
|
||||||
}
|
|
||||||
return templateEngine.process("application_form_template", context)
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun buildLatexExportModel(applicationForm: ApplicationForm): LatexExportModel {
|
|
||||||
val dateFormatter = DateTimeFormatter.ofPattern("dd.MM.yyyy")
|
|
||||||
|
|
||||||
return LatexExportModel(
|
|
||||||
id = applicationForm.id,
|
|
||||||
name = LatexEscaper.escape(applicationForm.name),
|
|
||||||
organizationId = LatexEscaper.escape(applicationForm.organizationId),
|
|
||||||
employer = LatexEscaper.escape("Arbeitgeber der Organisation ${applicationForm.organizationId}"),
|
|
||||||
worksCouncil = LatexEscaper.escape("Betriebsrat der Organisation ${applicationForm.organizationId}"),
|
|
||||||
createdAt = applicationForm.createdAt?.atZone(ZoneId.of("Europe/Berlin"))?.format(dateFormatter) ?: "",
|
|
||||||
sections =
|
|
||||||
applicationForm.formElementSections.map { section ->
|
|
||||||
LatexSection(
|
|
||||||
title = LatexEscaper.escape(section.title),
|
|
||||||
description = LatexEscaper.escape(section.description),
|
|
||||||
subsections =
|
|
||||||
section.formElementSubSections.map { subsection ->
|
|
||||||
LatexSubSection(
|
|
||||||
title = LatexEscaper.escape(subsection.title),
|
|
||||||
subtitle = LatexEscaper.escape(subsection.subtitle),
|
|
||||||
elements =
|
|
||||||
subsection.formElements.map { element ->
|
|
||||||
LatexFormElement(
|
|
||||||
title = LatexEscaper.escape(element.title),
|
|
||||||
description = LatexEscaper.escape(element.description),
|
|
||||||
value = renderElementValue(element),
|
|
||||||
)
|
|
||||||
},
|
|
||||||
)
|
|
||||||
},
|
|
||||||
)
|
|
||||||
},
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun buildLatexExportModel(
|
private fun buildLatexExportModel(
|
||||||
snapshot: ApplicationFormSnapshotDto,
|
snapshot: ApplicationFormSnapshotDto,
|
||||||
createdAt: Instant?,
|
createdAt: Instant?,
|
||||||
@@ -153,48 +87,6 @@ class ApplicationFormFormatService(
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun renderElementValue(element: FormElement): String =
|
|
||||||
when (element.type.name) {
|
|
||||||
"TEXTFIELD", "TEXTAREA" -> {
|
|
||||||
val value = element.options.firstOrNull()?.value
|
|
||||||
if (value.isNullOrBlank()) "Keine Eingabe" else LatexEscaper.escape(value)
|
|
||||||
}
|
|
||||||
"DATE" -> {
|
|
||||||
val value = element.options.firstOrNull()?.value
|
|
||||||
if (value.isNullOrBlank()) {
|
|
||||||
"Kein Datum ausgewählt"
|
|
||||||
} else {
|
|
||||||
try {
|
|
||||||
LocalDate.parse(value).format(DateTimeFormatter.ofPattern("dd.MM.yyyy"))
|
|
||||||
} catch (e: Exception) {
|
|
||||||
LatexEscaper.escape(value)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
"RICH_TEXT" -> {
|
|
||||||
val value = element.options.firstOrNull()?.value
|
|
||||||
if (value.isNullOrBlank()) "Keine Eingabe" else richTextToLatexConverter.convertToLatex(value)
|
|
||||||
}
|
|
||||||
"SELECT", "CHECKBOX" -> {
|
|
||||||
val selected = element.options.filter { it.value == "true" }.map { it.label }
|
|
||||||
if (selected.isEmpty()) {
|
|
||||||
"Keine Auswahl getroffen"
|
|
||||||
} else {
|
|
||||||
selected.joinToString(
|
|
||||||
", ",
|
|
||||||
) { LatexEscaper.escape(it) }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
"RADIOBUTTON" -> {
|
|
||||||
val selected = element.options.firstOrNull { it.value == "true" }?.label
|
|
||||||
if (selected == null) "Keine Auswahl getroffen" else LatexEscaper.escape(selected)
|
|
||||||
}
|
|
||||||
"SWITCH" -> {
|
|
||||||
if (element.options.any { it.value == "true" }) "Ja" else "Nein"
|
|
||||||
}
|
|
||||||
else -> "Keine Auswahl getroffen"
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun renderElementValue(element: FormElementSnapshotDto): String =
|
private fun renderElementValue(element: FormElementSnapshotDto): String =
|
||||||
when (element.type.name) {
|
when (element.type.name) {
|
||||||
"TEXTFIELD", "TEXTAREA" -> {
|
"TEXTFIELD", "TEXTAREA" -> {
|
||||||
@@ -237,66 +129,6 @@ class ApplicationFormFormatService(
|
|||||||
else -> "Keine Auswahl getroffen"
|
else -> "Keine Auswahl getroffen"
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun filterVisibleElements(applicationForm: ApplicationForm): ApplicationForm {
|
|
||||||
val allElements = collectAllFormElements(applicationForm)
|
|
||||||
val formElementsByRef = buildFormElementsByRefMap(allElements)
|
|
||||||
val visibilityMap = evaluateVisibility(allElements, formElementsByRef)
|
|
||||||
|
|
||||||
val filteredSections =
|
|
||||||
applicationForm.formElementSections
|
|
||||||
.filter { !it.isTemplate }
|
|
||||||
.mapNotNull { section ->
|
|
||||||
val filteredSubSections =
|
|
||||||
section.formElementSubSections
|
|
||||||
.mapNotNull { subsection ->
|
|
||||||
val filteredElements =
|
|
||||||
subsection.formElements.filter { element ->
|
|
||||||
visibilityMap[element.id] ?: true
|
|
||||||
}
|
|
||||||
if (filteredElements.isEmpty()) {
|
|
||||||
null
|
|
||||||
} else {
|
|
||||||
FormElementSubSection(
|
|
||||||
id = subsection.id,
|
|
||||||
title = subsection.title,
|
|
||||||
subtitle = subsection.subtitle,
|
|
||||||
formElements = filteredElements.toMutableList(),
|
|
||||||
formElementSection = null,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (filteredSubSections.isEmpty()) {
|
|
||||||
null
|
|
||||||
} else {
|
|
||||||
FormElementSection(
|
|
||||||
id = section.id,
|
|
||||||
title = section.title,
|
|
||||||
shortTitle = section.shortTitle,
|
|
||||||
description = section.description,
|
|
||||||
isTemplate = section.isTemplate,
|
|
||||||
templateReference = section.templateReference,
|
|
||||||
titleTemplate = section.titleTemplate,
|
|
||||||
spawnedFromElementReference = section.spawnedFromElementReference,
|
|
||||||
formElementSubSections = filteredSubSections.toMutableList(),
|
|
||||||
applicationForm = null,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return ApplicationForm(
|
|
||||||
id = applicationForm.id,
|
|
||||||
name = applicationForm.name,
|
|
||||||
status = applicationForm.status,
|
|
||||||
createdBy = applicationForm.createdBy,
|
|
||||||
lastModifiedBy = applicationForm.lastModifiedBy,
|
|
||||||
createdAt = applicationForm.createdAt,
|
|
||||||
modifiedAt = applicationForm.modifiedAt,
|
|
||||||
isTemplate = applicationForm.isTemplate,
|
|
||||||
organizationId = applicationForm.organizationId,
|
|
||||||
formElementSections = filteredSections.toMutableList(),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun filterVisibleElements(snapshot: ApplicationFormSnapshotDto): ApplicationFormSnapshotDto {
|
private fun filterVisibleElements(snapshot: ApplicationFormSnapshotDto): ApplicationFormSnapshotDto {
|
||||||
val allElements = collectAllFormElements(snapshot)
|
val allElements = collectAllFormElements(snapshot)
|
||||||
val formElementsByRef = buildSnapshotFormElementsByRefMap(allElements)
|
val formElementsByRef = buildSnapshotFormElementsByRefMap(allElements)
|
||||||
@@ -319,21 +151,11 @@ class ApplicationFormFormatService(
|
|||||||
return snapshot.copy(sections = filteredSections)
|
return snapshot.copy(sections = filteredSections)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun collectAllFormElements(applicationForm: ApplicationForm): List<FormElement> =
|
|
||||||
applicationForm.formElementSections
|
|
||||||
.flatMap { it.formElementSubSections }
|
|
||||||
.flatMap { it.formElements }
|
|
||||||
|
|
||||||
private fun collectAllFormElements(snapshot: ApplicationFormSnapshotDto): List<FormElementSnapshotDto> =
|
private fun collectAllFormElements(snapshot: ApplicationFormSnapshotDto): List<FormElementSnapshotDto> =
|
||||||
snapshot.sections
|
snapshot.sections
|
||||||
.flatMap(FormElementSectionSnapshotDto::subsections)
|
.flatMap(FormElementSectionSnapshotDto::subsections)
|
||||||
.flatMap(FormElementSubSectionSnapshotDto::elements)
|
.flatMap(FormElementSubSectionSnapshotDto::elements)
|
||||||
|
|
||||||
private fun buildFormElementsByRefMap(allElements: List<FormElement>): Map<String, FormElement> =
|
|
||||||
allElements
|
|
||||||
.mapNotNull { elem -> elem.reference?.let { it to elem } }
|
|
||||||
.toMap()
|
|
||||||
|
|
||||||
private fun buildSnapshotFormElementsByRefMap(
|
private fun buildSnapshotFormElementsByRefMap(
|
||||||
allElements: List<FormElementSnapshotDto>,
|
allElements: List<FormElementSnapshotDto>,
|
||||||
): Map<String, FormElementSnapshotDto> =
|
): Map<String, FormElementSnapshotDto> =
|
||||||
@@ -341,38 +163,6 @@ class ApplicationFormFormatService(
|
|||||||
.mapNotNull { elem -> elem.reference?.let { it to elem } }
|
.mapNotNull { elem -> elem.reference?.let { it to elem } }
|
||||||
.toMap()
|
.toMap()
|
||||||
|
|
||||||
private fun evaluateVisibility(
|
|
||||||
allElements: List<FormElement>,
|
|
||||||
formElementsByRef: Map<String, FormElement>,
|
|
||||||
): Map<UUID?, Boolean> {
|
|
||||||
val visibilityMap = mutableMapOf<UUID?, Boolean>()
|
|
||||||
|
|
||||||
allElements.forEach { element ->
|
|
||||||
visibilityMap[element.id] = isElementVisible(element, formElementsByRef)
|
|
||||||
}
|
|
||||||
|
|
||||||
return visibilityMap
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun isElementVisible(
|
|
||||||
element: FormElement,
|
|
||||||
formElementsByRef: Map<String, FormElement>,
|
|
||||||
): Boolean {
|
|
||||||
val condition = element.visibilityCondition ?: return true
|
|
||||||
|
|
||||||
// Don't show if source element is missing
|
|
||||||
val sourceElement = formElementsByRef[condition.sourceFormElementReference] ?: return false
|
|
||||||
|
|
||||||
val sourceValue = getFormElementValue(sourceElement)
|
|
||||||
val conditionMet =
|
|
||||||
evaluateCondition(sourceValue, condition.formElementExpectedValue, condition.formElementOperator)
|
|
||||||
|
|
||||||
return when (condition.formElementConditionType) {
|
|
||||||
VisibilityConditionType.SHOW -> conditionMet
|
|
||||||
VisibilityConditionType.HIDE -> !conditionMet
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun isElementVisible(
|
private fun isElementVisible(
|
||||||
element: FormElementSnapshotDto,
|
element: FormElementSnapshotDto,
|
||||||
formElementsByRef: Map<String, FormElementSnapshotDto>,
|
formElementsByRef: Map<String, FormElementSnapshotDto>,
|
||||||
@@ -391,17 +181,6 @@ class ApplicationFormFormatService(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun getFormElementValue(element: FormElement): String =
|
|
||||||
when (element.type.name) {
|
|
||||||
"SELECT",
|
|
||||||
"RADIOBUTTON",
|
|
||||||
-> element.options.firstOrNull { it.value == "true" }?.label ?: ""
|
|
||||||
"CHECKBOX",
|
|
||||||
"SWITCH",
|
|
||||||
-> if (element.options.any { it.value == "true" }) "true" else "false"
|
|
||||||
else -> element.options.firstOrNull()?.value ?: ""
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun getFormElementValue(element: FormElementSnapshotDto): String =
|
private fun getFormElementValue(element: FormElementSnapshotDto): String =
|
||||||
when (element.type.name) {
|
when (element.type.name) {
|
||||||
"SELECT",
|
"SELECT",
|
||||||
@@ -413,18 +192,6 @@ class ApplicationFormFormatService(
|
|||||||
else -> element.options.firstOrNull()?.value ?: ""
|
else -> element.options.firstOrNull()?.value ?: ""
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun evaluateCondition(
|
|
||||||
actualValue: String,
|
|
||||||
expectedValue: String,
|
|
||||||
operator: VisibilityConditionOperator,
|
|
||||||
): Boolean =
|
|
||||||
when (operator) {
|
|
||||||
VisibilityConditionOperator.EQUALS -> actualValue.equals(expectedValue, ignoreCase = true)
|
|
||||||
VisibilityConditionOperator.NOT_EQUALS -> !actualValue.equals(expectedValue, ignoreCase = true)
|
|
||||||
VisibilityConditionOperator.IS_EMPTY -> actualValue.isEmpty()
|
|
||||||
VisibilityConditionOperator.IS_NOT_EMPTY -> actualValue.isNotEmpty()
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun evaluateCondition(
|
private fun evaluateCondition(
|
||||||
actualValue: String,
|
actualValue: String,
|
||||||
expectedValue: String,
|
expectedValue: String,
|
||||||
|
|||||||
@@ -1,223 +0,0 @@
|
|||||||
<!DOCTYPE html>
|
|
||||||
<html xmlns:th="http://www.thymeleaf.org">
|
|
||||||
<head>
|
|
||||||
<meta charset="UTF-8"/>
|
|
||||||
<title th:text="${applicationForm.name}"></title>
|
|
||||||
<style>
|
|
||||||
body {
|
|
||||||
font-family: 'Times New Roman', Times, serif;
|
|
||||||
line-height: 1.4;
|
|
||||||
margin: 40px;
|
|
||||||
color: #333;
|
|
||||||
}
|
|
||||||
|
|
||||||
header {
|
|
||||||
text-align: center;
|
|
||||||
margin-bottom: 40px;
|
|
||||||
}
|
|
||||||
|
|
||||||
header img.logo {
|
|
||||||
max-height: 80px;
|
|
||||||
margin-bottom: 10px;
|
|
||||||
}
|
|
||||||
|
|
||||||
header h1 {
|
|
||||||
font-size: 1.8em;
|
|
||||||
letter-spacing: 1px;
|
|
||||||
margin: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.meta {
|
|
||||||
margin-bottom: 30px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.meta .field {
|
|
||||||
margin-bottom: 5px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.meta label {
|
|
||||||
font-weight: bold;
|
|
||||||
display: inline-block;
|
|
||||||
width: 150px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.contract-section {
|
|
||||||
margin-bottom: 25px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.contract-section h2 {
|
|
||||||
font-size: 1.3em;
|
|
||||||
border-bottom: 1px solid #aaa;
|
|
||||||
padding-bottom: 5px;
|
|
||||||
margin-bottom: 15px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.form-section {
|
|
||||||
margin-bottom: 30px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.form-section h3 {
|
|
||||||
font-size: 1.2em;
|
|
||||||
color: #444;
|
|
||||||
margin-bottom: 10px;
|
|
||||||
border-bottom: 1px solid #ddd;
|
|
||||||
padding-bottom: 5px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.form-section p.description {
|
|
||||||
font-style: italic;
|
|
||||||
color: #666;
|
|
||||||
margin: 5px 0 15px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.form-subsection {
|
|
||||||
margin-left: 10px;
|
|
||||||
margin-bottom: 20px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.form-subsection h4 {
|
|
||||||
font-size: 1.15em;
|
|
||||||
color: #555;
|
|
||||||
margin-bottom: 8px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.form-subsection p.description {
|
|
||||||
font-style: italic;
|
|
||||||
color: #666;
|
|
||||||
margin: 5px 0 10px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.form-element {
|
|
||||||
margin-bottom: 20px;
|
|
||||||
margin-left: 20px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.form-element h5 {
|
|
||||||
font-size: 1.05em;
|
|
||||||
margin-bottom: 5px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.form-element p.description {
|
|
||||||
font-style: italic;
|
|
||||||
color: #666;
|
|
||||||
margin: 5px 0 10px;
|
|
||||||
}
|
|
||||||
|
|
||||||
footer {
|
|
||||||
text-align: center;
|
|
||||||
font-size: 0.9em;
|
|
||||||
color: #666;
|
|
||||||
margin-top: 50px;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
<header>
|
|
||||||
<h1 th:text="${applicationForm.name}"></h1>
|
|
||||||
</header>
|
|
||||||
|
|
||||||
<div class="meta">
|
|
||||||
<div class="field">
|
|
||||||
<label>ID:</label>
|
|
||||||
<span th:text="${applicationForm.id}"></span>
|
|
||||||
</div>
|
|
||||||
<div class="field">
|
|
||||||
<label>Erstellt von:</label>
|
|
||||||
<span th:text="${applicationForm.createdBy.name}"></span>
|
|
||||||
</div>
|
|
||||||
<div class="field">
|
|
||||||
<label>Erstellt am:</label>
|
|
||||||
<span th:text="${#temporals.format(applicationForm.createdAt, 'dd.MM.yyyy')}"></span>
|
|
||||||
</div>
|
|
||||||
<div class="field">
|
|
||||||
<label>Organisation:</label>
|
|
||||||
<span th:text="${applicationForm.organizationId}"></span>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="contract-section">
|
|
||||||
<h2>Formularelemente</h2>
|
|
||||||
<div th:each="section : ${applicationForm.formElementSections}" class="form-section">
|
|
||||||
<h3 th:text="${section.title}"></h3>
|
|
||||||
<p class="description" th:if="${section.description}" th:text="${section.description}"></p>
|
|
||||||
|
|
||||||
<div th:each="subsection : ${section.formElementSubSections}" class="form-subsection">
|
|
||||||
<h4 th:text="${subsection.title}"></h4>
|
|
||||||
<p class="description" th:if="${subsection.subtitle}" th:text="${subsection.subtitle}"></p>
|
|
||||||
|
|
||||||
<div th:each="elem : ${subsection.formElements}" class="form-element">
|
|
||||||
<h5 th:text="${elem.title}"></h5>
|
|
||||||
<p class="description" th:if="${elem.description}" th:text="${elem.description}"></p>
|
|
||||||
|
|
||||||
<div th:switch="${elem.type.name()}">
|
|
||||||
<div th:case="'TEXTFIELD'">
|
|
||||||
<div th:each="option : ${elem.options}">
|
|
||||||
<p th:if="${!option.value.isEmpty()}" th:text="${option.value}"></p>
|
|
||||||
</div>
|
|
||||||
<p th:if="${elem.options.isEmpty() || elem.options.?[!value.isEmpty()].isEmpty()}">Keine Eingabe</p>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div th:case="'TEXTAREA'">
|
|
||||||
<div th:each="option : ${elem.options}">
|
|
||||||
<p th:if="${!option.value.isEmpty()}" th:text="${option.value}"></p>
|
|
||||||
</div>
|
|
||||||
<p th:if="${elem.options.isEmpty() || elem.options.?[!value.isEmpty()].isEmpty()}">Keine Eingabe</p>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div th:case="'DATE'">
|
|
||||||
<div th:each="option : ${elem.options}">
|
|
||||||
<p th:if="${!option.value.isEmpty()}"
|
|
||||||
th:with="dateValue=${#temporals.createDate(option.value, 'yyyy-MM-dd')}"
|
|
||||||
th:text="${#temporals.format(dateValue, 'dd.MM.yyyy')}"></p>
|
|
||||||
</div>
|
|
||||||
<p th:if="${elem.options.isEmpty() || elem.options.?[!value.isEmpty()].isEmpty()}">Kein Datum ausgewählt</p>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div th:case="'RICH_TEXT'">
|
|
||||||
<div th:each="option : ${elem.options}">
|
|
||||||
<div th:if="${!option.value.isEmpty()}" th:utext="${option.value}"></div>
|
|
||||||
</div>
|
|
||||||
<p th:if="${elem.options.isEmpty() || elem.options.?[!value.isEmpty()].isEmpty()}">Keine Eingabe</p>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div th:case="'SELECT'">
|
|
||||||
<ul>
|
|
||||||
<li th:each="option : ${elem.options}" th:if="${option.value == 'true'}" th:text="${option.label}"></li>
|
|
||||||
</ul>
|
|
||||||
<p th:if="${elem.options.?[value == 'true'].isEmpty()}">Keine Auswahl getroffen</p>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div th:case="'RADIOBUTTON'">
|
|
||||||
<p th:each="option : ${elem.options}" th:if="${option.value == 'true'}" th:text="${option.label}"></p>
|
|
||||||
<p th:if="${elem.options.?[value == 'true'].isEmpty()}">Keine Auswahl getroffen</p>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div th:case="'CHECKBOX'">
|
|
||||||
<ul>
|
|
||||||
<li th:each="option : ${elem.options}" th:if="${option.value == 'true'}" th:text="${option.label}"></li>
|
|
||||||
</ul>
|
|
||||||
<p th:if="${elem.options.?[value == 'true'].isEmpty()}">Keine Auswahl getroffen</p>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div th:case="'SWITCH'">
|
|
||||||
<p th:if="${elem.options.?[value == 'true'].isEmpty()}">Nein</p>
|
|
||||||
<p th:if="${!elem.options.?[value == 'true'].isEmpty()}">Ja</p>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div th:case="*">
|
|
||||||
<ul>
|
|
||||||
<li th:each="option : ${elem.options}" th:if="${option.value == 'true'}" th:text="${option.label}"></li>
|
|
||||||
</ul>
|
|
||||||
<p th:if="${elem.options.?[value == 'true'].isEmpty()}">Keine Auswahl getroffen</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<footer>
|
|
||||||
<p>Dieses Dokument wurde automatisch erzeugt und ist ohne Unterschrift gültig.</p>
|
|
||||||
</footer>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
||||||
Reference in New Issue
Block a user