feat(fullstack): Add test application form creation
This commit is contained in:
@@ -203,9 +203,10 @@ const { isSwiping } = usePointerSwipe(stepperScrollEl, {
|
||||
const previousVisibilityMap = ref<Map<string, boolean>>(new Map())
|
||||
|
||||
const allFormElements = computed(() => {
|
||||
return props.formElementSections
|
||||
.filter((section) => section.isTemplate !== true)
|
||||
.flatMap((section) => section.formElementSubSections?.flatMap((subsection) => subsection.formElements) ?? [])
|
||||
const nonTemplateSections = props.formElementSections.filter((section) => section.isTemplate !== true)
|
||||
return nonTemplateSections.flatMap(
|
||||
(section) => section.formElementSubSections?.flatMap((subsection) => subsection.formElements) ?? []
|
||||
)
|
||||
})
|
||||
|
||||
const visibilityMap = computed(() => {
|
||||
@@ -407,15 +408,34 @@ function handleFormElementUpdate(updatedFormElements: FormElementDto[], subsecti
|
||||
}
|
||||
|
||||
function clearNewlyHiddenFormElements(sections: FormElementSectionDto[]): FormElementSectionDto[] {
|
||||
const allElements = sections.flatMap(
|
||||
// Only evaluate visibility for non-template sections to avoid duplicate reference issues
|
||||
const nonTemplateSections = sections.filter((section) => section.isTemplate !== true)
|
||||
const allElements = nonTemplateSections.flatMap(
|
||||
(section) => section.formElementSubSections?.flatMap((subsection) => subsection.formElements) ?? []
|
||||
)
|
||||
const newVisibilityMap = evaluateFormElementVisibility(allElements)
|
||||
|
||||
const clearedSections = clearHiddenFormElementValues(sections, previousVisibilityMap.value, newVisibilityMap)
|
||||
// Only clear values in non-template sections, preserve template sections unchanged
|
||||
const clearedNonTemplateSections = clearHiddenFormElementValues(
|
||||
nonTemplateSections,
|
||||
previousVisibilityMap.value,
|
||||
newVisibilityMap
|
||||
)
|
||||
previousVisibilityMap.value = newVisibilityMap
|
||||
|
||||
return clearedSections
|
||||
// Create a map of cleared sections by their identity for lookup
|
||||
const clearedSectionMap = new Map<FormElementSectionDto, FormElementSectionDto>()
|
||||
nonTemplateSections.forEach((original, index) => {
|
||||
clearedSectionMap.set(original, clearedNonTemplateSections[index]!)
|
||||
})
|
||||
|
||||
// Preserve original order: replace non-template sections with cleared versions, keep templates unchanged
|
||||
return sections.map((section) => {
|
||||
if (section.isTemplate === true) {
|
||||
return section
|
||||
}
|
||||
return clearedSectionMap.get(section) ?? section
|
||||
})
|
||||
}
|
||||
|
||||
function getSubsectionKey(
|
||||
|
||||
@@ -0,0 +1,73 @@
|
||||
import { useUserStore } from '~~/stores/useUserStore'
|
||||
import { useTestDataApi } from '~/composables/testing/useTestDataApi'
|
||||
|
||||
/**
|
||||
* TESTING-ONLY FEATURE
|
||||
*
|
||||
* One-click duplicator for the seeded demo application form "SAP S/4HANA".
|
||||
*
|
||||
* This version uses a dedicated backend endpoint to ensure reliability:
|
||||
* 1. Loads the seeded YAML on the backend.
|
||||
* 2. Creates a fresh ApplicationForm entity with new IDs.
|
||||
* 3. Sets current user as creator.
|
||||
* 4. Assigns the form to the currently selected organization.
|
||||
*/
|
||||
export function useSeededSapS4HanaDuplicator() {
|
||||
const { t } = useI18n()
|
||||
const logger = useLogger().withTag('seeded-sap-duplicator')
|
||||
const toast = useToast()
|
||||
|
||||
const { canWriteApplicationForms } = usePermissions()
|
||||
const userStore = useUserStore()
|
||||
const { selectedOrganization } = storeToRefs(userStore)
|
||||
|
||||
const isDuplicating = ref(false)
|
||||
|
||||
const showButton = computed(() => canWriteApplicationForms.value)
|
||||
|
||||
async function duplicateSapS4HanaForTesting() {
|
||||
if (isDuplicating.value) return
|
||||
|
||||
const organizationId = selectedOrganization.value?.id
|
||||
if (!organizationId) {
|
||||
toast.add({
|
||||
title: t('common.error'),
|
||||
description: 'Please select an organization first.',
|
||||
color: 'error'
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
isDuplicating.value = true
|
||||
try {
|
||||
const { createTestDataApplicationForm } = useTestDataApi()
|
||||
|
||||
const created = await createTestDataApplicationForm(organizationId)
|
||||
|
||||
toast.add({
|
||||
title: t('common.success'),
|
||||
description: 'Created a new test application form.',
|
||||
color: 'success'
|
||||
})
|
||||
|
||||
if (created?.id) {
|
||||
await navigateTo(`/application-forms/${created.id}/0`)
|
||||
}
|
||||
} catch (e: unknown) {
|
||||
logger.error('Failed creating test application form via backend:', e)
|
||||
toast.add({
|
||||
title: t('common.error'),
|
||||
description: 'Failed to create test application form. Check backend logs.',
|
||||
color: 'error'
|
||||
})
|
||||
} finally {
|
||||
isDuplicating.value = false
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
showButton,
|
||||
isDuplicating,
|
||||
duplicateSapS4HanaForTesting
|
||||
}
|
||||
}
|
||||
24
legalconsenthub/app/composables/testing/useTestDataApi.ts
Normal file
24
legalconsenthub/app/composables/testing/useTestDataApi.ts
Normal file
@@ -0,0 +1,24 @@
|
||||
import { TestDataApi, Configuration, type ApplicationFormDto } from '~~/.api-client'
|
||||
import { cleanDoubleSlashes, withoutTrailingSlash } from 'ufo'
|
||||
import { wrappedFetchWrap } from '~/utils/wrappedFetch'
|
||||
|
||||
export function useTestDataApi() {
|
||||
const appBaseUrl = useRuntimeConfig().app.baseURL
|
||||
const { serverApiBasePath, clientProxyBasePath } = useRuntimeConfig().public
|
||||
|
||||
const basePath = withoutTrailingSlash(
|
||||
cleanDoubleSlashes(import.meta.client ? appBaseUrl + clientProxyBasePath : clientProxyBasePath + serverApiBasePath)
|
||||
)
|
||||
|
||||
const testDataApiClient = new TestDataApi(
|
||||
new Configuration({ basePath, fetchApi: wrappedFetchWrap(useRequestFetch()) })
|
||||
)
|
||||
|
||||
async function createTestDataApplicationForm(organizationId: string): Promise<ApplicationFormDto> {
|
||||
return testDataApiClient.createTestDataApplicationForm({ organizationId })
|
||||
}
|
||||
|
||||
return {
|
||||
createTestDataApplicationForm
|
||||
}
|
||||
}
|
||||
@@ -25,7 +25,18 @@
|
||||
|
||||
<template #footer="{ collapsed }">
|
||||
<UserMenu :collapsed="collapsed" />
|
||||
<UButton @click="copyAccessTokenToClipboard">📋</UButton>
|
||||
<UButton
|
||||
v-if="showSapCopyButton"
|
||||
:loading="isDuplicatingSapForm"
|
||||
:disabled="isDuplicatingSapForm"
|
||||
icon="i-lucide-copy"
|
||||
size="xs"
|
||||
variant="soft"
|
||||
@click="duplicateSapS4HanaForTesting"
|
||||
>
|
||||
🖨
|
||||
</UButton>
|
||||
<UButton size="xs" variant="soft" @click="copyAccessTokenToClipboard">📋</UButton>
|
||||
</template>
|
||||
</UDashboardSidebar>
|
||||
|
||||
@@ -37,6 +48,7 @@
|
||||
|
||||
<script setup lang="ts">
|
||||
import { useNotificationStore } from '~~/stores/useNotificationStore'
|
||||
import { useSeededSapS4HanaDuplicator } from '~/composables/testing/useSeededSapS4HanaDuplicator'
|
||||
|
||||
const { t: $t } = useI18n()
|
||||
|
||||
@@ -65,6 +77,12 @@ const isNotificationsSlideoverOpen = ref(false)
|
||||
const notificationStore = useNotificationStore()
|
||||
const { hasUnread } = storeToRefs(notificationStore)
|
||||
|
||||
const {
|
||||
showButton: showSapCopyButton,
|
||||
isDuplicating: isDuplicatingSapForm,
|
||||
duplicateSapS4HanaForTesting
|
||||
} = useSeededSapS4HanaDuplicator()
|
||||
|
||||
onMounted(async () => {
|
||||
await notificationStore.fetchUnreadCount()
|
||||
notificationStore.startPeriodicRefresh()
|
||||
|
||||
Reference in New Issue
Block a user