feat(fullstack): Add test application form creation

This commit is contained in:
2026-01-31 08:58:35 +01:00
parent 954c6d00e1
commit b279e6cc17
8 changed files with 326 additions and 14 deletions

View File

@@ -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(

View File

@@ -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
}
}

View 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
}
}

View File

@@ -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()