feat(fullstack): Add form element section and stepper
This commit is contained in:
@@ -665,7 +665,7 @@ components:
|
|||||||
required:
|
required:
|
||||||
- id
|
- id
|
||||||
- name
|
- name
|
||||||
- formElements
|
- formElementSections
|
||||||
- isTemplate
|
- isTemplate
|
||||||
- organizationId
|
- organizationId
|
||||||
- createdBy
|
- createdBy
|
||||||
@@ -678,10 +678,10 @@ components:
|
|||||||
format: uuid
|
format: uuid
|
||||||
name:
|
name:
|
||||||
type: string
|
type: string
|
||||||
formElements:
|
formElementSections:
|
||||||
type: array
|
type: array
|
||||||
items:
|
items:
|
||||||
$ref: "#/components/schemas/FormElementDto"
|
$ref: "#/components/schemas/FormElementSectionDto"
|
||||||
isTemplate:
|
isTemplate:
|
||||||
type: boolean
|
type: boolean
|
||||||
organizationId:
|
organizationId:
|
||||||
@@ -700,16 +700,16 @@ components:
|
|||||||
CreateApplicationFormDto:
|
CreateApplicationFormDto:
|
||||||
required:
|
required:
|
||||||
- name
|
- name
|
||||||
- formElements
|
- formElementSections
|
||||||
- isTemplate
|
- isTemplate
|
||||||
type: object
|
type: object
|
||||||
properties:
|
properties:
|
||||||
name:
|
name:
|
||||||
type: string
|
type: string
|
||||||
formElements:
|
formElementSections:
|
||||||
type: array
|
type: array
|
||||||
items:
|
items:
|
||||||
$ref: "#/components/schemas/CreateFormElementDto"
|
$ref: "#/components/schemas/CreateFormElementSectionDto"
|
||||||
isTemplate:
|
isTemplate:
|
||||||
type: boolean
|
type: boolean
|
||||||
default: false
|
default: false
|
||||||
@@ -728,21 +728,64 @@ components:
|
|||||||
items:
|
items:
|
||||||
$ref: "#/components/schemas/ApplicationFormDto"
|
$ref: "#/components/schemas/ApplicationFormDto"
|
||||||
|
|
||||||
|
|
||||||
####### Form #######
|
####### Form #######
|
||||||
FormElementDto:
|
FormElementSectionDto:
|
||||||
type: object
|
type: object
|
||||||
required:
|
required:
|
||||||
- id
|
- id
|
||||||
|
- title
|
||||||
|
- formElements
|
||||||
- applicationFormId
|
- applicationFormId
|
||||||
- options
|
|
||||||
- type
|
|
||||||
properties:
|
properties:
|
||||||
id:
|
id:
|
||||||
type: string
|
type: string
|
||||||
format: uuid
|
format: uuid
|
||||||
|
title:
|
||||||
|
type: string
|
||||||
|
shortTitle:
|
||||||
|
type: string
|
||||||
|
description:
|
||||||
|
type: string
|
||||||
|
formElements:
|
||||||
|
type: array
|
||||||
|
items:
|
||||||
|
$ref: "#/components/schemas/FormElementDto"
|
||||||
applicationFormId:
|
applicationFormId:
|
||||||
type: string
|
type: string
|
||||||
format: uuid
|
format: uuid
|
||||||
|
|
||||||
|
CreateFormElementSectionDto:
|
||||||
|
type: object
|
||||||
|
required:
|
||||||
|
- title
|
||||||
|
- formElements
|
||||||
|
properties:
|
||||||
|
id:
|
||||||
|
type: string
|
||||||
|
format: uuid
|
||||||
|
title:
|
||||||
|
type: string
|
||||||
|
shortTitle:
|
||||||
|
type: string
|
||||||
|
description:
|
||||||
|
type: string
|
||||||
|
formElements:
|
||||||
|
type: array
|
||||||
|
items:
|
||||||
|
$ref: "#/components/schemas/CreateFormElementDto"
|
||||||
|
|
||||||
|
FormElementDto:
|
||||||
|
type: object
|
||||||
|
required:
|
||||||
|
- id
|
||||||
|
- options
|
||||||
|
- type
|
||||||
|
- formElementSectionId
|
||||||
|
properties:
|
||||||
|
id:
|
||||||
|
type: string
|
||||||
|
format: uuid
|
||||||
title:
|
title:
|
||||||
type: string
|
type: string
|
||||||
description:
|
description:
|
||||||
@@ -753,6 +796,9 @@ components:
|
|||||||
$ref: "#/components/schemas/FormOptionDto"
|
$ref: "#/components/schemas/FormOptionDto"
|
||||||
type:
|
type:
|
||||||
$ref: "#/components/schemas/FormElementType"
|
$ref: "#/components/schemas/FormElementType"
|
||||||
|
formElementSectionId:
|
||||||
|
type: string
|
||||||
|
format: uuid
|
||||||
|
|
||||||
CreateFormElementDto:
|
CreateFormElementDto:
|
||||||
type: object
|
type: object
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
package com.betriebsratkanzlei.legalconsenthub.application_form
|
package com.betriebsratkanzlei.legalconsenthub.application_form
|
||||||
|
|
||||||
import com.betriebsratkanzlei.legalconsenthub.form_element.FormElement
|
import com.betriebsratkanzlei.legalconsenthub.form_element.FormElementSection
|
||||||
import com.betriebsratkanzlei.legalconsenthub.user.User
|
import com.betriebsratkanzlei.legalconsenthub.user.User
|
||||||
import jakarta.persistence.AttributeOverride
|
import jakarta.persistence.AttributeOverride
|
||||||
import jakarta.persistence.AttributeOverrides
|
import jakarta.persistence.AttributeOverrides
|
||||||
@@ -29,7 +29,7 @@ class ApplicationForm(
|
|||||||
var name: String = "",
|
var name: String = "",
|
||||||
|
|
||||||
@OneToMany(mappedBy = "applicationForm", cascade = [CascadeType.ALL], orphanRemoval = true)
|
@OneToMany(mappedBy = "applicationForm", cascade = [CascadeType.ALL], orphanRemoval = true)
|
||||||
var formElements: MutableList<FormElement> = mutableListOf(),
|
var formElementSections: MutableList<FormElementSection> = mutableListOf(),
|
||||||
|
|
||||||
@Column(nullable = false)
|
@Column(nullable = false)
|
||||||
var isTemplate: Boolean,
|
var isTemplate: Boolean,
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
package com.betriebsratkanzlei.legalconsenthub.application_form
|
package com.betriebsratkanzlei.legalconsenthub.application_form
|
||||||
|
|
||||||
import com.betriebsratkanzlei.legalconsenthub.form_element.FormElementMapper
|
import com.betriebsratkanzlei.legalconsenthub.form_element.FormElementSectionMapper
|
||||||
import com.betriebsratkanzlei.legalconsenthub.security.CustomJwtTokenPrincipal
|
import com.betriebsratkanzlei.legalconsenthub.security.CustomJwtTokenPrincipal
|
||||||
import com.betriebsratkanzlei.legalconsenthub.user.User
|
import com.betriebsratkanzlei.legalconsenthub.user.User
|
||||||
import com.betriebsratkanzlei.legalconsenthub.user.UserMapper
|
import com.betriebsratkanzlei.legalconsenthub.user.UserMapper
|
||||||
@@ -11,12 +11,12 @@ import org.springframework.stereotype.Component
|
|||||||
import java.time.LocalDateTime
|
import java.time.LocalDateTime
|
||||||
|
|
||||||
@Component
|
@Component
|
||||||
class ApplicationFormMapper(private val formElementMapper: FormElementMapper, private val userMapper: UserMapper) {
|
class ApplicationFormMapper(private val formElementSectionMapper: FormElementSectionMapper, private val userMapper: UserMapper) {
|
||||||
fun toApplicationFormDto(applicationForm: ApplicationForm): ApplicationFormDto {
|
fun toApplicationFormDto(applicationForm: ApplicationForm): ApplicationFormDto {
|
||||||
return ApplicationFormDto(
|
return ApplicationFormDto(
|
||||||
id = applicationForm.id ?: throw IllegalStateException("ApplicationForm ID must not be null!"),
|
id = applicationForm.id ?: throw IllegalStateException("ApplicationForm ID must not be null!"),
|
||||||
name = applicationForm.name,
|
name = applicationForm.name,
|
||||||
formElements = applicationForm.formElements.map { formElementMapper.toFormElementDto(it) },
|
formElementSections = applicationForm.formElementSections.map { formElementSectionMapper.toFormElementSectionDto(it) },
|
||||||
isTemplate = applicationForm.isTemplate,
|
isTemplate = applicationForm.isTemplate,
|
||||||
organizationId = applicationForm.organizationId,
|
organizationId = applicationForm.organizationId,
|
||||||
createdBy = userMapper.toUserDto(applicationForm.createdBy),
|
createdBy = userMapper.toUserDto(applicationForm.createdBy),
|
||||||
@@ -30,7 +30,7 @@ class ApplicationFormMapper(private val formElementMapper: FormElementMapper, pr
|
|||||||
return ApplicationForm(
|
return ApplicationForm(
|
||||||
id = applicationForm.id,
|
id = applicationForm.id,
|
||||||
name = applicationForm.name,
|
name = applicationForm.name,
|
||||||
formElements = applicationForm.formElements.map { formElementMapper.toFormElement(it) }.toMutableList(),
|
formElementSections = applicationForm.formElementSections.map { formElementSectionMapper.toFormElementSection(it) }.toMutableList(),
|
||||||
isTemplate = applicationForm.isTemplate,
|
isTemplate = applicationForm.isTemplate,
|
||||||
organizationId = applicationForm.organizationId,
|
organizationId = applicationForm.organizationId,
|
||||||
createdBy = userMapper.toUser(applicationForm.createdBy),
|
createdBy = userMapper.toUser(applicationForm.createdBy),
|
||||||
@@ -53,8 +53,8 @@ class ApplicationFormMapper(private val formElementMapper: FormElementMapper, pr
|
|||||||
createdBy = createdBy,
|
createdBy = createdBy,
|
||||||
lastModifiedBy = lastModifiedBy,
|
lastModifiedBy = lastModifiedBy,
|
||||||
)
|
)
|
||||||
applicationForm.formElements = createApplicationFormDto.formElements
|
applicationForm.formElementSections = createApplicationFormDto.formElementSections
|
||||||
.map { formElementMapper.toFormElement(it, applicationForm) }
|
.map { formElementSectionMapper.toFormElementSection(it, applicationForm) }
|
||||||
.toMutableList()
|
.toMutableList()
|
||||||
return applicationForm
|
return applicationForm
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,5 @@
|
|||||||
|
package com.betriebsratkanzlei.legalconsenthub.error
|
||||||
|
|
||||||
|
import java.util.UUID
|
||||||
|
|
||||||
|
class FormElementSectionNotFoundException(id: UUID): RuntimeException("Couldn't find form element section with ID: $id")
|
||||||
@@ -1,18 +1,16 @@
|
|||||||
package com.betriebsratkanzlei.legalconsenthub.form_element;
|
package com.betriebsratkanzlei.legalconsenthub.form_element;
|
||||||
|
|
||||||
import com.betriebsratkanzlei.legalconsenthub.application_form.ApplicationForm
|
import com.betriebsratkanzlei.legalconsenthub.application_form.ApplicationForm
|
||||||
import com.betriebsratkanzlei.legalconsenthub.comment.Comment
|
|
||||||
import com.betriebsratkanzlei.legalconsenthub_api.model.FormElementType
|
import com.betriebsratkanzlei.legalconsenthub_api.model.FormElementType
|
||||||
import jakarta.persistence.CascadeType
|
|
||||||
import jakarta.persistence.CollectionTable
|
import jakarta.persistence.CollectionTable
|
||||||
import jakarta.persistence.Column
|
import jakarta.persistence.Column
|
||||||
import jakarta.persistence.ElementCollection
|
import jakarta.persistence.ElementCollection
|
||||||
|
import jakarta.persistence.Embeddable
|
||||||
import jakarta.persistence.Entity
|
import jakarta.persistence.Entity
|
||||||
import jakarta.persistence.GeneratedValue;
|
import jakarta.persistence.GeneratedValue;
|
||||||
import jakarta.persistence.Id;
|
import jakarta.persistence.Id;
|
||||||
import jakarta.persistence.JoinColumn
|
import jakarta.persistence.JoinColumn
|
||||||
import jakarta.persistence.ManyToOne
|
import jakarta.persistence.ManyToOne
|
||||||
import jakarta.persistence.OneToMany
|
|
||||||
|
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
|
|
||||||
@@ -22,10 +20,6 @@ class FormElement(
|
|||||||
@GeneratedValue
|
@GeneratedValue
|
||||||
var id: UUID? = null,
|
var id: UUID? = null,
|
||||||
|
|
||||||
@ManyToOne
|
|
||||||
@JoinColumn(name = "application_form_id", nullable = false)
|
|
||||||
var applicationForm: ApplicationForm? = null,
|
|
||||||
|
|
||||||
var title: String? = null,
|
var title: String? = null,
|
||||||
|
|
||||||
var description: String? = null,
|
var description: String? = null,
|
||||||
@@ -35,5 +29,9 @@ class FormElement(
|
|||||||
var options: MutableList<FormOption> = mutableListOf(),
|
var options: MutableList<FormOption> = mutableListOf(),
|
||||||
|
|
||||||
@Column(nullable = false)
|
@Column(nullable = false)
|
||||||
var type: FormElementType
|
var type: FormElementType,
|
||||||
|
|
||||||
|
@ManyToOne
|
||||||
|
@JoinColumn(name = "form_element_section_id", nullable = false)
|
||||||
|
var formElementSection: FormElementSection? = null
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -1,8 +1,6 @@
|
|||||||
package com.betriebsratkanzlei.legalconsenthub.form_element
|
package com.betriebsratkanzlei.legalconsenthub.form_element
|
||||||
|
|
||||||
import com.betriebsratkanzlei.legalconsenthub.application_form.ApplicationForm
|
import com.betriebsratkanzlei.legalconsenthub.error.FormElementSectionNotFoundException
|
||||||
import com.betriebsratkanzlei.legalconsenthub.application_form.ApplicationFormRepository
|
|
||||||
import com.betriebsratkanzlei.legalconsenthub.error.ApplicationFormNotFoundException
|
|
||||||
import com.betriebsratkanzlei.legalconsenthub_api.model.CreateFormElementDto
|
import com.betriebsratkanzlei.legalconsenthub_api.model.CreateFormElementDto
|
||||||
import com.betriebsratkanzlei.legalconsenthub_api.model.FormElementDto
|
import com.betriebsratkanzlei.legalconsenthub_api.model.FormElementDto
|
||||||
import org.springframework.stereotype.Component
|
import org.springframework.stereotype.Component
|
||||||
@@ -10,7 +8,7 @@ import org.springframework.stereotype.Component
|
|||||||
@Component
|
@Component
|
||||||
class FormElementMapper(
|
class FormElementMapper(
|
||||||
private val formOptionMapper: FormOptionMapper,
|
private val formOptionMapper: FormOptionMapper,
|
||||||
private val applicationFormRepository: ApplicationFormRepository
|
private val formElementSectionRepository: FormElementSectionRepository
|
||||||
) {
|
) {
|
||||||
fun toFormElementDto(formElement: FormElement): FormElementDto {
|
fun toFormElementDto(formElement: FormElement): FormElementDto {
|
||||||
return FormElementDto(
|
return FormElementDto(
|
||||||
@@ -19,14 +17,14 @@ class FormElementMapper(
|
|||||||
description = formElement.description,
|
description = formElement.description,
|
||||||
options = formElement.options.map { formOptionMapper.toFormOptionDto(it) },
|
options = formElement.options.map { formOptionMapper.toFormOptionDto(it) },
|
||||||
type = formElement.type,
|
type = formElement.type,
|
||||||
applicationFormId = formElement.applicationForm?.id
|
formElementSectionId = formElement.formElementSection?.id
|
||||||
?: throw IllegalStateException("ApplicationForm ID must not be null!")
|
?: throw IllegalStateException("FormElementSection ID must not be null!")
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun toFormElement(formElement: FormElementDto): FormElement {
|
fun toFormElement(formElement: FormElementDto): FormElement {
|
||||||
val applicationForm = applicationFormRepository.findById(formElement.applicationFormId)
|
val formElementSection = formElementSectionRepository.findById(formElement.formElementSectionId)
|
||||||
.orElseThrow { ApplicationFormNotFoundException(formElement.applicationFormId) }
|
.orElseThrow { FormElementSectionNotFoundException(formElement.formElementSectionId) }
|
||||||
|
|
||||||
return FormElement(
|
return FormElement(
|
||||||
id = formElement.id,
|
id = formElement.id,
|
||||||
@@ -34,18 +32,18 @@ class FormElementMapper(
|
|||||||
description = formElement.description,
|
description = formElement.description,
|
||||||
options = formElement.options.map { formOptionMapper.toFormOption(it) }.toMutableList(),
|
options = formElement.options.map { formOptionMapper.toFormOption(it) }.toMutableList(),
|
||||||
type = formElement.type,
|
type = formElement.type,
|
||||||
applicationForm = applicationForm
|
formElementSection = formElementSection
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun toFormElement(formElement: CreateFormElementDto, applicationForm: ApplicationForm): FormElement {
|
fun toFormElement(formElement: CreateFormElementDto, formElementSection: FormElementSection): FormElement {
|
||||||
return FormElement(
|
return FormElement(
|
||||||
id = null,
|
id = null,
|
||||||
title = formElement.title,
|
title = formElement.title,
|
||||||
description = formElement.description,
|
description = formElement.description,
|
||||||
options = formElement.options.map { formOptionMapper.toFormOption(it) }.toMutableList(),
|
options = formElement.options.map { formOptionMapper.toFormOption(it) }.toMutableList(),
|
||||||
type = formElement.type,
|
type = formElement.type,
|
||||||
applicationForm = applicationForm
|
formElementSection = formElementSection
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,36 @@
|
|||||||
|
package com.betriebsratkanzlei.legalconsenthub.form_element;
|
||||||
|
|
||||||
|
import com.betriebsratkanzlei.legalconsenthub.application_form.ApplicationForm
|
||||||
|
import jakarta.persistence.CascadeType
|
||||||
|
import jakarta.persistence.CollectionTable
|
||||||
|
import jakarta.persistence.Column
|
||||||
|
import jakarta.persistence.ElementCollection
|
||||||
|
import jakarta.persistence.Entity
|
||||||
|
import jakarta.persistence.GeneratedValue;
|
||||||
|
import jakarta.persistence.Id;
|
||||||
|
import jakarta.persistence.JoinColumn
|
||||||
|
import jakarta.persistence.ManyToOne
|
||||||
|
import jakarta.persistence.OneToMany
|
||||||
|
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
|
@Entity
|
||||||
|
class FormElementSection(
|
||||||
|
@Id
|
||||||
|
@GeneratedValue
|
||||||
|
var id: UUID? = null,
|
||||||
|
|
||||||
|
@Column(nullable = false)
|
||||||
|
var title: String,
|
||||||
|
|
||||||
|
var shortTitle: String? = null,
|
||||||
|
|
||||||
|
var description: String? = null,
|
||||||
|
|
||||||
|
@OneToMany(mappedBy = "formElementSection", cascade = [CascadeType.ALL], orphanRemoval = true)
|
||||||
|
var formElements: MutableList<FormElement> = mutableListOf(),
|
||||||
|
|
||||||
|
@ManyToOne
|
||||||
|
@JoinColumn(name = "application_form_id", nullable = false)
|
||||||
|
var applicationForm: ApplicationForm? = null,
|
||||||
|
)
|
||||||
@@ -0,0 +1,53 @@
|
|||||||
|
package com.betriebsratkanzlei.legalconsenthub.form_element
|
||||||
|
|
||||||
|
import com.betriebsratkanzlei.legalconsenthub.application_form.ApplicationForm
|
||||||
|
import com.betriebsratkanzlei.legalconsenthub.application_form.ApplicationFormRepository
|
||||||
|
import com.betriebsratkanzlei.legalconsenthub.error.ApplicationFormNotFoundException
|
||||||
|
import com.betriebsratkanzlei.legalconsenthub_api.model.CreateFormElementSectionDto
|
||||||
|
import com.betriebsratkanzlei.legalconsenthub_api.model.FormElementSectionDto
|
||||||
|
import org.springframework.stereotype.Component
|
||||||
|
|
||||||
|
@Component
|
||||||
|
class FormElementSectionMapper(
|
||||||
|
private val formElementMapper: FormElementMapper,
|
||||||
|
private val applicationFormRepository: ApplicationFormRepository
|
||||||
|
) {
|
||||||
|
fun toFormElementSectionDto(formElementSection: FormElementSection): FormElementSectionDto {
|
||||||
|
return FormElementSectionDto(
|
||||||
|
id = formElementSection.id ?: throw IllegalStateException("FormElementSection ID must not be null!"),
|
||||||
|
title = formElementSection.title,
|
||||||
|
description = formElementSection.description,
|
||||||
|
shortTitle = formElementSection.shortTitle,
|
||||||
|
formElements = formElementSection.formElements.map { formElementMapper.toFormElementDto(it) },
|
||||||
|
applicationFormId = formElementSection.applicationForm?.id
|
||||||
|
?: throw IllegalStateException("ApplicationForm ID must not be null!")
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun toFormElementSection(formElementSection: FormElementSectionDto): FormElementSection {
|
||||||
|
val applicationForm = applicationFormRepository.findById(formElementSection.applicationFormId)
|
||||||
|
.orElseThrow { ApplicationFormNotFoundException(formElementSection.applicationFormId) }
|
||||||
|
|
||||||
|
return FormElementSection(
|
||||||
|
id = formElementSection.id,
|
||||||
|
title = formElementSection.title,
|
||||||
|
description = formElementSection.description,
|
||||||
|
shortTitle = formElementSection.shortTitle,
|
||||||
|
formElements = formElementSection.formElements.map { formElementMapper.toFormElement(it) }.toMutableList(),
|
||||||
|
applicationForm = applicationForm
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun toFormElementSection(createFormElementSection: CreateFormElementSectionDto, applicationForm: ApplicationForm): FormElementSection {
|
||||||
|
val formElementSection = FormElementSection(
|
||||||
|
title = createFormElementSection.title,
|
||||||
|
description = createFormElementSection.description,
|
||||||
|
shortTitle = createFormElementSection.shortTitle,
|
||||||
|
applicationForm = applicationForm
|
||||||
|
)
|
||||||
|
formElementSection.formElements = createFormElementSection.formElements
|
||||||
|
.map { formElementMapper.toFormElement(it, formElementSection) }
|
||||||
|
.toMutableList()
|
||||||
|
return formElementSection
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
package com.betriebsratkanzlei.legalconsenthub.form_element
|
||||||
|
|
||||||
|
import org.springframework.data.jpa.repository.JpaRepository
|
||||||
|
import org.springframework.stereotype.Repository
|
||||||
|
import java.util.UUID
|
||||||
|
|
||||||
|
@Repository
|
||||||
|
interface FormElementSectionRepository : JpaRepository<FormElementSection, UUID>
|
||||||
@@ -50,7 +50,7 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import type { FormElementDto, FormOptionDto } from '~/.api-client'
|
import type { CommentDto, FormElementDto, FormOptionDto } from '~/.api-client'
|
||||||
import { useComment } from '~/composables/comment/useComment'
|
import { useComment } from '~/composables/comment/useComment'
|
||||||
import { resolveComponent } from 'vue'
|
import { resolveComponent } from 'vue'
|
||||||
|
|
||||||
|
|||||||
@@ -1,82 +0,0 @@
|
|||||||
<template>
|
|
||||||
<UDashboardPanel id="home">
|
|
||||||
<template #header>
|
|
||||||
<UDashboardNavbar title="Home" :ui="{ right: 'gap-3' }">
|
|
||||||
<template #leading>
|
|
||||||
<UDashboardSidebarCollapse />
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<template #right>
|
|
||||||
<UDropdownMenu :items="items">
|
|
||||||
<UButton icon="i-lucide-plus" size="md" class="rounded-full" />
|
|
||||||
</UDropdownMenu>
|
|
||||||
</template>
|
|
||||||
</UDashboardNavbar>
|
|
||||||
|
|
||||||
<UDashboardToolbar>
|
|
||||||
<template #left> toolbar left </template>
|
|
||||||
</UDashboardToolbar>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<template #body>
|
|
||||||
<div class="flex flex-col w-full lg:max-w-4xl mx-auto">
|
|
||||||
<UCard variant="subtle">
|
|
||||||
<FormEngine
|
|
||||||
v-if="applicationForm"
|
|
||||||
v-model="applicationForm.formElements"
|
|
||||||
:application-form-id="applicationForm.id"
|
|
||||||
:disabled="isReadOnly"
|
|
||||||
@click:comments="openComments"
|
|
||||||
/>
|
|
||||||
<UButton :disabled="isReadOnly" class="my-3 lg:my-4" @click="onSubmit">Submit</UButton>
|
|
||||||
</UCard>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
</UDashboardPanel>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script setup lang="ts">
|
|
||||||
import type { ApplicationFormDto } from '~/.api-client'
|
|
||||||
|
|
||||||
const { getApplicationFormById, updateApplicationForm } = useApplicationForm()
|
|
||||||
const route = useRoute()
|
|
||||||
const { user } = useAuth()
|
|
||||||
|
|
||||||
const items = [
|
|
||||||
[
|
|
||||||
{
|
|
||||||
label: 'Neuer Mitbestimmungsantrag',
|
|
||||||
icon: 'i-lucide-send',
|
|
||||||
to: '/create'
|
|
||||||
}
|
|
||||||
]
|
|
||||||
]
|
|
||||||
|
|
||||||
const { data } = await useAsyncData<ApplicationFormDto>(async () => {
|
|
||||||
return await getApplicationFormById(Array.isArray(route.params.id) ? route.params.id[0] : route.params.id)
|
|
||||||
})
|
|
||||||
|
|
||||||
const applicationForm = computed({
|
|
||||||
get: () => data?.value,
|
|
||||||
set: (val) => {
|
|
||||||
if (val && data.value) {
|
|
||||||
data.value = val
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
const isReadOnly = computed(() => {
|
|
||||||
return applicationForm.value?.createdBy.id !== user.value?.id
|
|
||||||
})
|
|
||||||
|
|
||||||
async function onSubmit() {
|
|
||||||
if (data?.value) {
|
|
||||||
await updateApplicationForm(data.value.id, data.value)
|
|
||||||
await navigateTo('/')
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function openComments(formElementId: string) {
|
|
||||||
console.log('open comments for', formElementId)
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
159
legalconsenthub/pages/application-forms/[id]/[sectionIndex].vue
Normal file
159
legalconsenthub/pages/application-forms/[id]/[sectionIndex].vue
Normal file
@@ -0,0 +1,159 @@
|
|||||||
|
<template>
|
||||||
|
<UDashboardPanel id="home">
|
||||||
|
<template #header>
|
||||||
|
<UDashboardNavbar title="Home" :ui="{ right: 'gap-3' }">
|
||||||
|
<template #leading>
|
||||||
|
<UDashboardSidebarCollapse />
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<template #right>
|
||||||
|
<UDropdownMenu :items="items">
|
||||||
|
<UButton icon="i-lucide-plus" size="md" class="rounded-full" />
|
||||||
|
</UDropdownMenu>
|
||||||
|
</template>
|
||||||
|
</UDashboardNavbar>
|
||||||
|
|
||||||
|
<UDashboardToolbar>
|
||||||
|
<template #left> toolbar left </template>
|
||||||
|
</UDashboardToolbar>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<template #body>
|
||||||
|
<div class="flex flex-col w-full lg:max-w-4xl mx-auto">
|
||||||
|
<UStepper ref="stepper" v-model="activeStepperItemIndex" :items="stepperItems" class="w-full" />
|
||||||
|
<h1 class="text-xl text-pretty font-bold text-highlighted">
|
||||||
|
{{ currentFormElementSection.title }}
|
||||||
|
</h1>
|
||||||
|
<UCard variant="subtle">
|
||||||
|
<FormEngine
|
||||||
|
v-if="applicationForm"
|
||||||
|
v-model="currentFormElementSection.formElements"
|
||||||
|
:application-form-id="applicationForm.id"
|
||||||
|
:disabled="isReadOnly"
|
||||||
|
@click:comments="openComments"
|
||||||
|
/>
|
||||||
|
<div class="flex gap-2 justify-between mt-4">
|
||||||
|
<UButton
|
||||||
|
leading-icon="i-lucide-arrow-left"
|
||||||
|
:disabled="!stepper?.hasPrev"
|
||||||
|
@click="navigateStepper('backward')"
|
||||||
|
>
|
||||||
|
Prev
|
||||||
|
</UButton>
|
||||||
|
|
||||||
|
<UButton
|
||||||
|
v-if="stepper?.hasNext"
|
||||||
|
trailing-icon="i-lucide-arrow-right"
|
||||||
|
:disabled="!stepper?.hasNext"
|
||||||
|
@click="navigateStepper('forward')"
|
||||||
|
>
|
||||||
|
Next
|
||||||
|
</UButton>
|
||||||
|
<UButton
|
||||||
|
v-if="!stepper?.hasNext"
|
||||||
|
trailing-icon="i-lucide-send-horizontal"
|
||||||
|
:disabled="isReadOnly"
|
||||||
|
@click="onSubmit"
|
||||||
|
>
|
||||||
|
Submit
|
||||||
|
</UButton>
|
||||||
|
</div>
|
||||||
|
</UCard>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
</UDashboardPanel>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
import type { ApplicationFormDto, FormElementSectionDto } from '~/.api-client'
|
||||||
|
import type { StepperItem } from '@nuxt/ui'
|
||||||
|
|
||||||
|
const { getApplicationFormById, updateApplicationForm } = useApplicationForm()
|
||||||
|
const route = useRoute()
|
||||||
|
const { user } = useAuth()
|
||||||
|
|
||||||
|
const items = [
|
||||||
|
[
|
||||||
|
{
|
||||||
|
label: 'Neuer Mitbestimmungsantrag',
|
||||||
|
icon: 'i-lucide-send',
|
||||||
|
to: '/create'
|
||||||
|
}
|
||||||
|
]
|
||||||
|
]
|
||||||
|
|
||||||
|
const stepper = useTemplateRef('stepper')
|
||||||
|
const activeStepperItemIndex = ref<number>(0)
|
||||||
|
|
||||||
|
const currentFormElementSection = computed<FormElementSectionDto>(() => {
|
||||||
|
return applicationForm.value?.formElementSections[activeStepperItemIndex.value]
|
||||||
|
})
|
||||||
|
|
||||||
|
watch(activeStepperItemIndex, async (newActiveStepperItem: number) => {
|
||||||
|
activeStepperItemIndex.value = newActiveStepperItem
|
||||||
|
await navigateTo(`/application-forms/${route.params.id}/${newActiveStepperItem}`)
|
||||||
|
})
|
||||||
|
|
||||||
|
watch(
|
||||||
|
() => route.path,
|
||||||
|
(_) => {
|
||||||
|
const sectionIndex = parseInt(route.params.sectionIndex[0])
|
||||||
|
activeStepperItemIndex.value = !isNaN(sectionIndex) ? sectionIndex : 0
|
||||||
|
},
|
||||||
|
{ immediate: true }
|
||||||
|
)
|
||||||
|
|
||||||
|
const { data, error } = await useAsyncData<ApplicationFormDto>(async () => {
|
||||||
|
return await getApplicationFormById(Array.isArray(route.params.id) ? route.params.id[0] : route.params.id)
|
||||||
|
})
|
||||||
|
|
||||||
|
if (error.value) {
|
||||||
|
throw createError({ statusText: error.value.message })
|
||||||
|
}
|
||||||
|
|
||||||
|
const applicationForm = computed<ApplicationFormDto>({
|
||||||
|
get: () => data?.value as ApplicationFormDto,
|
||||||
|
set: (val: ApplicationFormDto) => {
|
||||||
|
if (val && data.value) {
|
||||||
|
data.value = val
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
const isReadOnly = computed(() => {
|
||||||
|
return applicationForm.value?.createdBy.id !== user.value?.id
|
||||||
|
})
|
||||||
|
|
||||||
|
const stepperItems = computed(() => {
|
||||||
|
const stepperItems: StepperItem[] = []
|
||||||
|
applicationForm.value.formElementSections.forEach((section: FormElementSectionDto, index: number, _) => {
|
||||||
|
stepperItems.push({
|
||||||
|
title: section.shortTitle,
|
||||||
|
description: section.description
|
||||||
|
})
|
||||||
|
})
|
||||||
|
return stepperItems
|
||||||
|
})
|
||||||
|
|
||||||
|
async function navigateStepper(direction: 'forward' | 'backward') {
|
||||||
|
if (direction === 'forward') {
|
||||||
|
stepper.value?.next()
|
||||||
|
} else {
|
||||||
|
stepper.value?.prev()
|
||||||
|
}
|
||||||
|
const targetSectionIndex =
|
||||||
|
direction === 'forward' ? activeStepperItemIndex.value + 1 : activeStepperItemIndex.value - 1
|
||||||
|
await navigateTo(`/application-forms/${route.params.id}/${targetSectionIndex}`)
|
||||||
|
}
|
||||||
|
|
||||||
|
async function onSubmit() {
|
||||||
|
if (data?.value) {
|
||||||
|
await updateApplicationForm(data.value.id, data.value)
|
||||||
|
await navigateTo('/')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function openComments(formElementId: string) {
|
||||||
|
console.log('open comments for', formElementId)
|
||||||
|
}
|
||||||
|
</script>
|
||||||
@@ -26,8 +26,33 @@
|
|||||||
<UFormField label="Name">
|
<UFormField label="Name">
|
||||||
<UInput v-if="applicationFormTemplate" v-model="applicationFormTemplate.name" />
|
<UInput v-if="applicationFormTemplate" v-model="applicationFormTemplate.name" />
|
||||||
</UFormField>
|
</UFormField>
|
||||||
<FormEngine v-model="formElements" />
|
<UStepper ref="stepper" v-model="activeStepperItem" :items="stepperItems" class="w-full" />
|
||||||
<UButton type="submit">Submit</UButton>
|
<h1 v-if="currentFormElementSection?.title" class="text-xl text-pretty font-bold text-highlighted">
|
||||||
|
{{ currentFormElementSection.title }}
|
||||||
|
</h1>
|
||||||
|
<FormEngine
|
||||||
|
v-if="currentFormElementSection?.formElements"
|
||||||
|
v-model="currentFormElementSection.formElements"
|
||||||
|
/>
|
||||||
|
<div class="flex gap-2 justify-between mt-4">
|
||||||
|
<UButton
|
||||||
|
leading-icon="i-lucide-arrow-left"
|
||||||
|
:disabled="!stepper?.hasPrev"
|
||||||
|
@click="navigateStepper('backward')"
|
||||||
|
>
|
||||||
|
Prev
|
||||||
|
</UButton>
|
||||||
|
|
||||||
|
<UButton
|
||||||
|
v-if="stepper?.hasNext"
|
||||||
|
trailing-icon="i-lucide-arrow-right"
|
||||||
|
:disabled="!stepper?.hasNext"
|
||||||
|
@click="navigateStepper('forward')"
|
||||||
|
>
|
||||||
|
Next
|
||||||
|
</UButton>
|
||||||
|
<UButton v-if="!stepper?.hasNext" @click="onSubmit"> Submit </UButton>
|
||||||
|
</div>
|
||||||
</UForm>
|
</UForm>
|
||||||
</UPageCard>
|
</UPageCard>
|
||||||
</div>
|
</div>
|
||||||
@@ -36,20 +61,60 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { ComplianceStatus, type PagedApplicationFormDto } from '~/.api-client'
|
import { ComplianceStatus, type FormElementSectionDto, type PagedApplicationFormDto } from '~/.api-client'
|
||||||
import { useApplicationFormValidator } from '~/composables/useApplicationFormValidator'
|
import { useApplicationFormValidator } from '~/composables/useApplicationFormValidator'
|
||||||
import type { FormElementId } from '~/types/FormElement'
|
import type { FormElementId } from '~/types/FormElement'
|
||||||
|
import type { StepperItem } from '@nuxt/ui'
|
||||||
|
|
||||||
const { getAllApplicationFormTemplates } = useApplicationFormTemplate()
|
const { getAllApplicationFormTemplates } = useApplicationFormTemplate()
|
||||||
const { createApplicationForm } = useApplicationForm()
|
const { createApplicationForm } = useApplicationForm()
|
||||||
const { validateFormElements, getHighestComplianceStatus } = useApplicationFormValidator()
|
const { validateFormElements, getHighestComplianceStatus } = useApplicationFormValidator()
|
||||||
const { userDto, selectedOrganization } = useAuth()
|
const { userDto, selectedOrganization } = useAuth()
|
||||||
|
|
||||||
const { data } = await useAsyncData<PagedApplicationFormDto>(async () => {
|
const stepper = useTemplateRef('stepper')
|
||||||
|
const activeStepperItem = ref<number>(0)
|
||||||
|
|
||||||
|
const currentFormElementSection = computed(() => {
|
||||||
|
return applicationFormTemplate.value?.formElementSections[activeStepperItem.value]
|
||||||
|
})
|
||||||
|
|
||||||
|
watch(activeStepperItem, async (newActiveStepperItem: number) => {
|
||||||
|
activeStepperItem.value = newActiveStepperItem
|
||||||
|
})
|
||||||
|
|
||||||
|
const { data, error } = await useAsyncData<PagedApplicationFormDto>(async () => {
|
||||||
return await getAllApplicationFormTemplates()
|
return await getAllApplicationFormTemplates()
|
||||||
})
|
})
|
||||||
|
|
||||||
|
if (error.value) {
|
||||||
|
throw createError({ statusText: error.value.message })
|
||||||
|
}
|
||||||
|
|
||||||
|
const stepperItems = computed(() => {
|
||||||
|
const stepperItems: StepperItem[] = []
|
||||||
|
if (!applicationFormTemplate.value) {
|
||||||
|
return stepperItems
|
||||||
|
}
|
||||||
|
|
||||||
|
applicationFormTemplate.value.formElementSections.forEach((section: FormElementSectionDto) => {
|
||||||
|
stepperItems.push({
|
||||||
|
title: section.shortTitle,
|
||||||
|
description: section.description
|
||||||
|
})
|
||||||
|
})
|
||||||
|
return stepperItems
|
||||||
|
})
|
||||||
|
|
||||||
|
async function navigateStepper(direction: 'forward' | 'backward') {
|
||||||
|
if (direction === 'forward') {
|
||||||
|
stepper.value?.next()
|
||||||
|
} else {
|
||||||
|
stepper.value?.prev()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const applicationFormTemplate = computed({
|
const applicationFormTemplate = computed({
|
||||||
|
// TODO: Don't select always the first item, allow user to select a template
|
||||||
get: () => data?.value?.content[0] ?? undefined,
|
get: () => data?.value?.content[0] ?? undefined,
|
||||||
set: (val) => {
|
set: (val) => {
|
||||||
if (val && data.value) {
|
if (val && data.value) {
|
||||||
@@ -59,10 +124,11 @@ const applicationFormTemplate = computed({
|
|||||||
})
|
})
|
||||||
|
|
||||||
const formElements = computed({
|
const formElements = computed({
|
||||||
get: () => applicationFormTemplate.value?.formElements ?? [],
|
get: () => currentFormElementSection?.value?.formElements ?? [],
|
||||||
set: (val) => {
|
set: (val) => {
|
||||||
if (val && applicationFormTemplate.value) {
|
if (val && applicationFormTemplate.value) {
|
||||||
applicationFormTemplate.value.formElements = val
|
if (!currentFormElementSection.value) return
|
||||||
|
currentFormElementSection.value.formElements = val
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -36,7 +36,7 @@
|
|||||||
v-for="(applicationFormElem, index) in applicationForms"
|
v-for="(applicationFormElem, index) in applicationForms"
|
||||||
:key="applicationFormElem.id"
|
:key="applicationFormElem.id"
|
||||||
class="flex justify-between items-center p-4 bg-white rounded-lg shadow-md"
|
class="flex justify-between items-center p-4 bg-white rounded-lg shadow-md"
|
||||||
@click="navigateTo(`application-forms/${applicationFormElem.id}`)"
|
@click="navigateTo(`application-forms/${applicationFormElem.id}/0`)"
|
||||||
>
|
>
|
||||||
<div>
|
<div>
|
||||||
<p class="font-medium text-(--ui-text-highlighted) text-base">
|
<p class="font-medium text-(--ui-text-highlighted) text-base">
|
||||||
|
|||||||
154
testdata.json
154
testdata.json
@@ -3,83 +3,97 @@
|
|||||||
"name": "",
|
"name": "",
|
||||||
"createdBy": "Denis",
|
"createdBy": "Denis",
|
||||||
"lastModifiedBy": "Denis",
|
"lastModifiedBy": "Denis",
|
||||||
"formElements": [
|
"formElementSections": [
|
||||||
{
|
{
|
||||||
"title": "Zustimmung erforderlich",
|
"title": "Section 1",
|
||||||
"description": "Bitte wählen Sie eine Option aus, um fortzufahren.",
|
"shortTitle": "S1",
|
||||||
"options": [
|
"description": "First section of the form",
|
||||||
|
"formElements": [
|
||||||
{
|
{
|
||||||
"value": "false",
|
"title": "Zustimmung erforderlich",
|
||||||
"label": "Zustimmen (schwerwiegend)",
|
"description": "Bitte wählen Sie eine Option aus, um fortzufahren.",
|
||||||
"processingPurpose": "BUSINESS_PROCESS",
|
"options": [
|
||||||
"employeeDataCategory": "SENSITIVE"
|
{
|
||||||
}
|
"value": "false",
|
||||||
],
|
"label": "Zustimmen (schwerwiegend)",
|
||||||
"type": "SWITCH"
|
"processingPurpose": "BUSINESS_PROCESS",
|
||||||
},
|
"employeeDataCategory": "SENSITIVE"
|
||||||
{
|
}
|
||||||
"title": "Zustimmung erforderlich",
|
],
|
||||||
"description": "Bitte wählen Sie eine Option aus, um fortzufahren.",
|
"type": "SWITCH"
|
||||||
"options": [
|
|
||||||
{
|
|
||||||
"value": "false",
|
|
||||||
"label": "Zustimmen (keine Auswirkungen)",
|
|
||||||
"processingPurpose": "NONE",
|
|
||||||
"employeeDataCategory": "NONE"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"type": "SWITCH"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"title": "Zustimmung erforderlich",
|
|
||||||
"description": "Bitte wählen Sie eine Option aus, um fortzufahren.",
|
|
||||||
"options": [
|
|
||||||
{
|
|
||||||
"value": "false",
|
|
||||||
"label": "Zustimmen (Mittel)",
|
|
||||||
"processingPurpose": "DATA_ANALYSIS",
|
|
||||||
"employeeDataCategory": "REVIEW_REQUIRED"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"type": "CHECKBOX"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"title": "Eine weitere Zustimmung erforderlich",
|
|
||||||
"description": "Bitte wählen Sie eine Option aus, um fortzufahren.",
|
|
||||||
"options": [
|
|
||||||
{
|
|
||||||
"value": "false",
|
|
||||||
"label": "Zustimmen",
|
|
||||||
"processingPurpose": "BUSINESS_PROCESS",
|
|
||||||
"employeeDataCategory": "SENSITIVE"
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"value": "false",
|
"title": "Zustimmung erforderlich",
|
||||||
"label": "Ablehnen",
|
"description": "Bitte wählen Sie eine Option aus, um fortzufahren.",
|
||||||
"processingPurpose": "DATA_ANALYSIS",
|
"options": [
|
||||||
"employeeDataCategory": "REVIEW_REQUIRED"
|
{
|
||||||
}
|
"value": "false",
|
||||||
],
|
"label": "Zustimmen (keine Auswirkungen)",
|
||||||
"type": "SELECT"
|
"processingPurpose": "NONE",
|
||||||
},
|
"employeeDataCategory": "NONE"
|
||||||
{
|
}
|
||||||
"title": "Eine weitere Zustimmung erforderlich",
|
],
|
||||||
"description": "Bitte wählen Sie eine Option aus, um fortzufahren.",
|
"type": "SWITCH"
|
||||||
"options": [
|
|
||||||
{
|
|
||||||
"value": "false",
|
|
||||||
"label": "Zustimmen",
|
|
||||||
"processingPurpose": "BUSINESS_PROCESS",
|
|
||||||
"employeeDataCategory": "SENSITIVE"
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"value": "false",
|
"title": "Zustimmung erforderlich",
|
||||||
"label": "Ablehnen",
|
"description": "Bitte wählen Sie eine Option aus, um fortzufahren.",
|
||||||
"processingPurpose": "DATA_ANALYSIS",
|
"options": [
|
||||||
"employeeDataCategory": "REVIEW_REQUIRED"
|
{
|
||||||
|
"value": "false",
|
||||||
|
"label": "Zustimmen (Mittel)",
|
||||||
|
"processingPurpose": "DATA_ANALYSIS",
|
||||||
|
"employeeDataCategory": "REVIEW_REQUIRED"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"type": "CHECKBOX"
|
||||||
}
|
}
|
||||||
],
|
]
|
||||||
"type": "RADIOBUTTON"
|
},
|
||||||
|
{
|
||||||
|
"title": "Section 2",
|
||||||
|
"shortTitle": "S2",
|
||||||
|
"description": "Second section of the form",
|
||||||
|
"formElements": [
|
||||||
|
{
|
||||||
|
"title": "Eine weitere Zustimmung erforderlich",
|
||||||
|
"description": "Bitte wählen Sie eine Option aus, um fortzufahren.",
|
||||||
|
"options": [
|
||||||
|
{
|
||||||
|
"value": "false",
|
||||||
|
"label": "Zustimmen",
|
||||||
|
"processingPurpose": "BUSINESS_PROCESS",
|
||||||
|
"employeeDataCategory": "SENSITIVE"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"value": "false",
|
||||||
|
"label": "Ablehnen",
|
||||||
|
"processingPurpose": "DATA_ANALYSIS",
|
||||||
|
"employeeDataCategory": "REVIEW_REQUIRED"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"type": "SELECT"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"title": "Eine weitere Zustimmung erforderlich",
|
||||||
|
"description": "Bitte wählen Sie eine Option aus, um fortzufahren.",
|
||||||
|
"options": [
|
||||||
|
{
|
||||||
|
"value": "false",
|
||||||
|
"label": "Zustimmen",
|
||||||
|
"processingPurpose": "BUSINESS_PROCESS",
|
||||||
|
"employeeDataCategory": "SENSITIVE"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"value": "false",
|
||||||
|
"label": "Ablehnen",
|
||||||
|
"processingPurpose": "DATA_ANALYSIS",
|
||||||
|
"employeeDataCategory": "REVIEW_REQUIRED"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"type": "RADIOBUTTON"
|
||||||
|
}
|
||||||
|
]
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user