2. Zwischenstand
All checks were successful
Build and Push Docker Images / build-backend (push) Successful in 15s
Build and Push Docker Images / build-frontend (push) Successful in 2m43s

This commit is contained in:
2026-03-21 22:56:56 +01:00
parent 68b2cbb0ee
commit 03bcc1a939
56 changed files with 1289 additions and 1302 deletions

View File

@@ -51,7 +51,7 @@ const savingUser = ref(false)
const savingTenant = ref(false)
const creatingUser = ref(false)
const creatingTenant = ref(false)
const activeTab = ref(0)
const activeTab = ref("0")
const createUserModalOpen = ref(false)
const createTenantModalOpen = ref(false)
const createdUserPassword = ref("")
@@ -472,7 +472,7 @@ onMounted(async () => {
:items="tabItems"
class="admin-tabs h-full"
>
<template #item="{ item }">
<template #content="{ item }">
<div v-if="item.label === 'Benutzer'" class="admin-grid mt-5 grid grid-cols-1 xl:grid-cols-3 gap-5">
<UCard class="admin-card xl:col-span-1">
<div class="flex items-center justify-between mb-4">
@@ -494,7 +494,7 @@ onMounted(async () => {
v-if="!loading"
:data="userTableRows"
:columns="normalizedUserTableColumns"
@select="selectUser"
:on-select="selectUser"
/>
<USkeleton v-else class="h-80" />
@@ -519,49 +519,49 @@ onMounted(async () => {
</div>
<UForm :state="userForm" class="grid grid-cols-1 md:grid-cols-2 gap-6">
<UFormGroup label="E-Mail">
<UFormField label="E-Mail">
<UInput v-model="userForm.email" />
</UFormGroup>
</UFormField>
<UFormGroup label="Profil Vorname">
<UFormField label="Profil Vorname">
<UInput v-model="userForm.profile_defaults.first_name" />
</UFormGroup>
</UFormField>
<UFormGroup label="Profil Nachname">
<UFormField label="Profil Nachname">
<UInput v-model="userForm.profile_defaults.last_name" />
</UFormGroup>
</UFormField>
<UFormGroup label="Tenants">
<UFormField label="Tenants">
<USelectMenu
:model-value="userForm.tenant_ids"
:options="tenantOptions"
value-attribute="value"
option-attribute="label"
:items="tenantOptions"
value-key="value"
label-key="label"
multiple
@update:model-value="updateUserTenants"
/>
</UFormGroup>
</UFormField>
<UFormGroup label="Administrative Freigabe">
<UFormField label="Administrative Freigabe">
<div class="flex items-center gap-3 h-10">
<UToggle v-model="userForm.is_admin" />
<USwitch v-model="userForm.is_admin" />
<span class="text-sm text-gray-600">Darf Administrationsseite und Admin-API nutzen</span>
</div>
</UFormGroup>
</UFormField>
<UFormGroup label="Multi-Tenant">
<UFormField label="Multi-Tenant">
<div class="flex items-center gap-3 h-10">
<UToggle v-model="userForm.multiTenant" />
<USwitch v-model="userForm.multiTenant" />
<span class="text-sm text-gray-600">Benutzer darf mehreren Tenants zugeordnet sein</span>
</div>
</UFormGroup>
</UFormField>
<UFormGroup label="Passwortwechsel erzwingen">
<UFormField label="Passwortwechsel erzwingen">
<div class="flex items-center gap-3 h-10">
<UToggle v-model="userForm.must_change_password" />
<USwitch v-model="userForm.must_change_password" />
<span class="text-sm text-gray-600">Beim nächsten Login muss das Passwort geändert werden</span>
</div>
</UFormGroup>
</UFormField>
</UForm>
<div>
@@ -586,33 +586,33 @@ onMounted(async () => {
</div>
</div>
<UFormGroup label="Rolle">
<UFormField label="Rolle">
<USelectMenu
:model-value="getRoleForTenant(tenantId)"
:options="getRoleOptionsForTenant(tenantId)"
value-attribute="value"
option-attribute="label"
:items="getRoleOptionsForTenant(tenantId)"
value-key="value"
label-key="label"
placeholder="Rolle auswählen"
@update:model-value="(value) => setRoleForTenant(tenantId, value)"
/>
</UFormGroup>
</UFormField>
<UFormGroup label="Freies Profil">
<UFormField label="Freies Profil">
<USelectMenu
:model-value="getProfileAssignmentForTenant(tenantId)"
:options="[
:items="[
{ label: 'Neues Profil erzeugen', value: null },
...getFreeProfilesForTenant(tenantId).map((profile) => ({
label: profile.full_name || `${profile.first_name} ${profile.last_name}`,
value: profile.id,
}))
]"
value-attribute="value"
option-attribute="label"
value-key="value"
label-key="label"
placeholder="Profil auswählen"
@update:model-value="(value) => setProfileAssignmentForTenant(tenantId, value)"
/>
</UFormGroup>
</UFormField>
</div>
</UCard>
</div>
@@ -676,7 +676,7 @@ onMounted(async () => {
v-if="!loading"
:data="tenantTableRows"
:columns="normalizedTenantTableColumns"
@select="selectTenant"
:on-select="selectTenant"
/>
<USkeleton v-else class="h-80" />
@@ -701,13 +701,13 @@ onMounted(async () => {
</div>
<UForm :state="tenantForm" class="grid grid-cols-1 md:grid-cols-2 gap-6">
<UFormGroup label="Name">
<UFormField label="Name">
<UInput v-model="tenantForm.name" />
</UFormGroup>
</UFormField>
<UFormGroup label="Kürzel">
<UFormField label="Kürzel">
<UInput v-model="tenantForm.short" />
</UFormGroup>
</UFormField>
</UForm>
<div>
@@ -743,49 +743,50 @@ onMounted(async () => {
</UDashboardPanelContent>
<UModal v-model:open="createUserModalOpen">
<UCard>
<template #header>
<div class="text-lg font-semibold">Benutzer anlegen</div>
</template>
<template #content>
<UCard>
<template #header>
<div class="text-lg font-semibold">Benutzer anlegen</div>
</template>
<UForm
:state="createUserForm"
class="space-y-4"
@submit.prevent="createUser"
>
<UFormGroup label="E-Mail">
<UFormField label="E-Mail">
<UInput v-model="createUserForm.email" type="email" />
</UFormGroup>
</UFormField>
<UFormGroup label="Initialpasswort">
<UFormField label="Initialpasswort">
<UInput
v-model="createUserForm.password"
type="text"
placeholder="Leer lassen für automatisches Passwort"
/>
</UFormGroup>
</UFormField>
<UFormGroup label="Vorname für neues Profil">
<UFormField label="Vorname für neues Profil">
<UInput v-model="createUserForm.first_name" />
</UFormGroup>
</UFormField>
<UFormGroup label="Nachname für neues Profil">
<UFormField label="Nachname für neues Profil">
<UInput v-model="createUserForm.last_name" />
</UFormGroup>
</UFormField>
<UFormGroup label="Administrative Freigabe">
<UFormField label="Administrative Freigabe">
<div class="flex items-center gap-3 h-10">
<UToggle v-model="createUserForm.is_admin" />
<USwitch v-model="createUserForm.is_admin" />
<span class="text-sm text-gray-600">Benutzer darf die Administration öffnen</span>
</div>
</UFormGroup>
</UFormField>
<UFormGroup label="Multi-Tenant">
<UFormField label="Multi-Tenant">
<div class="flex items-center gap-3 h-10">
<UToggle v-model="createUserForm.multiTenant" />
<USwitch v-model="createUserForm.multiTenant" />
<span class="text-sm text-gray-600">Mehrere Tenant-Zuordnungen erlauben</span>
</div>
</UFormGroup>
</UFormField>
<div class="flex justify-end gap-3 pt-2">
<UButton color="gray" variant="soft" @click="createUserModalOpen = false">
@@ -795,28 +796,30 @@ onMounted(async () => {
Benutzer anlegen
</UButton>
</div>
</UForm>
</UCard>
</UForm>
</UCard>
</template>
</UModal>
<UModal v-model:open="createTenantModalOpen">
<UCard>
<template #header>
<div class="text-lg font-semibold">Tenant anlegen</div>
</template>
<template #content>
<UCard>
<template #header>
<div class="text-lg font-semibold">Tenant anlegen</div>
</template>
<UForm
:state="createTenantForm"
class="space-y-4"
@submit.prevent="createTenant"
>
<UFormGroup label="Name">
<UFormField label="Name">
<UInput v-model="createTenantForm.name" />
</UFormGroup>
</UFormField>
<UFormGroup label="Kürzel">
<UFormField label="Kürzel">
<UInput v-model="createTenantForm.short" />
</UFormGroup>
</UFormField>
<UAlert
title="Seed-Daten"
@@ -833,8 +836,9 @@ onMounted(async () => {
Tenant anlegen
</UButton>
</div>
</UForm>
</UCard>
</UForm>
</UCard>
</template>
</UModal>
<div class="mx-5 mb-5">

View File

@@ -101,16 +101,17 @@ setupPage()
+ Bankverbindung
</UButton>
<USlideover
v-model="showAddBankRequisition"
v-model:open="showAddBankRequisition"
>
<UCard
class="h-full"
>
<template #header>
<p>Bankverbindung hinzufügen</p>
</template>
<template #body>
<UCard
class="h-full"
>
<template #header>
<p>Bankverbindung hinzufügen</p>
</template>
<UFormGroup
<UFormField
label="BIC:"
class="flex-auto"
>
@@ -127,7 +128,7 @@ setupPage()
</UButton>
</InputGroup>
</UFormGroup>
</UFormField>
<UAlert
v-if="showAlert && bankData.id && bankData.countries.includes('DE')"
title="Bank gefunden"
@@ -137,46 +138,49 @@ setupPage()
class="mt-3"
:actions="[{ variant: 'solid', color: 'primary', label: 'Verbinden',click: generateLink }]"
/>
<UAlert
v-else-if="showAlert && !bankData.id"
title="Bank nicht gefunden"
icon="i-heroicons-x-circle"
color="error"
variant="outline"
class="mt-3"
/>
<UAlert
v-else-if="showAlert && !bankData.id"
title="Bank nicht gefunden"
icon="i-heroicons-x-circle"
color="error"
variant="outline"
class="mt-3"
/>
</UCard>
</UCard>
</template>
</USlideover>
</template>
</UDashboardNavbar>
<UModal v-model:open="showReqData">
<UCard>
<template #header>
Verfügbare Bankkonten
</template>
<div
v-for="account in reqData.accounts"
:key="account.id"
class="p-2 m-3 flex justify-between"
>
{{account.iban}} - {{account.owner_name}}
<template #content>
<UCard>
<template #header>
Verfügbare Bankkonten
</template>
<div
v-for="account in reqData.accounts"
:key="account.id"
class="p-2 m-3 flex justify-between"
>
{{account.iban}} - {{account.owner_name}}
<UButton
@click="addAccount(account)"
v-if="!bankaccounts.find(i => i.iban === account.iban)"
>
Hinzufügen
</UButton>
<UButton
@click="updateAccount(account)"
v-else
>
Aktualisieren
</UButton>
</div>
</UCard>
<UButton
@click="addAccount(account)"
v-if="!bankaccounts.find(i => i.iban === account.iban)"
>
Hinzufügen
</UButton>
<UButton
@click="updateAccount(account)"
v-else
>
Aktualisieren
</UButton>
</div>
</UCard>
</template>
</UModal>
<UTable
@@ -200,21 +204,21 @@ setupPage()
},
])"
>
<template #expired-data="{row}">
<span v-if="row.expired" class="text-rose-600">Ausgelaufen</span>
<template #expired-cell="{ row }">
<span v-if="row.original.expired" class="text-error-600">Ausgelaufen</span>
<span v-else class="text-primary">Aktiv</span>
<UButton
v-if="row.expired"
v-if="row.original.expired"
variant="outline"
class="ml-2"
@click="generateLink(row.bankId)"
@click="generateLink(row.original.bankId)"
>Aktualisieren</UButton>
</template>
<template #balance-data="{row}">
{{row.balance ? row.balance.toFixed(2).replace(".",",") + ' €' : '-'}}
<template #balance-cell="{ row }">
{{ row.original.balance ? row.original.balance.toFixed(2).replace(".",",") + ' €' : '-' }}
</template>
<template #iban-data="{row}">
{{row.iban.match(/.{1,5}/g).join(" ")}}
<template #iban-cell="{ row }">
{{ row.original.iban.match(/.{1,5}/g).join(" ") }}
</template>
</UTable>

View File

@@ -57,15 +57,15 @@ const saveAccount = async () => {
</template>
</UDashboardNavbar>
<UForm class="w-2/3 mx-auto mt-5">
<UFormGroup
<UFormField
label="E-Mail Adresse"
>
<UInput
v-model="itemInfo.email"
/>
</UFormGroup>
</UFormField>
<UFormGroup
<UFormField
label="Passwort"
>
<UInput
@@ -73,61 +73,61 @@ const saveAccount = async () => {
v-model="itemInfo.password"
placeholder="********"
/>
</UFormGroup>
</UFormField>
<USeparator label="IMAP"/>
<UFormGroup
<UFormField
label="IMAP Host"
>
<UInput
v-model="itemInfo.imap_host"
/>
</UFormGroup>
</UFormField>
<UFormGroup
<UFormField
label="IMAP Port"
>
<UInput
type="number"
v-model="itemInfo.imap_port"
/>
</UFormGroup>
</UFormField>
<UFormGroup
<UFormField
label="IMAP SSL"
>
<UToggle
<USwitch
v-model="itemInfo.imap_ssl"
/>
</UFormGroup>
</UFormField>
<USeparator label="SMTP"/>
<UFormGroup
<UFormField
label="SMTP Host"
>
<UInput
v-model="itemInfo.smtp_host"
/>
</UFormGroup>
</UFormField>
<UFormGroup
<UFormField
label="SMTP Port"
>
<UInput
type="number"
v-model="itemInfo.smtp_port"
/>
</UFormGroup>
</UFormField>
<UFormGroup
<UFormField
label="SMTP SSL"
>
<UToggle
<USwitch
v-model="itemInfo.smtp_ssl"
/>
</UFormGroup>
</UFormField>
</UForm>
</template>

View File

@@ -32,23 +32,23 @@ const columns = computed(() => templateColumns.filter((column) => selectedColumn
<template>
<UModal
v-model="showEmailAddressModal"
v-model:open="showEmailAddressModal"
>
<template #content>
<UCard>
<template #header>
E-Mail Adresse
</template>
<!-- <UFormGroup
<!-- <UFormField
label="E-Mail Adresse:"
>
</UFormGroup>-->
</UFormField>-->
<UInput
v-model="createEMailAddress"
/>
<!-- <UFormGroup
<!-- <UFormField
label="Account Typ:"
>
<USelectMenu
@@ -57,7 +57,7 @@ const columns = computed(() => templateColumns.filter((column) => selectedColumn
value-attribute="key"
v-model="createEMailType"
/>
</UFormGroup>-->
</UFormField>-->
<template #footer>
<UButton
@click="createAccount"
@@ -85,9 +85,9 @@ const columns = computed(() => templateColumns.filter((column) => selectedColumn
:data="items"
:columns="normalizeTableColumns(columns)"
class="w-full"
@select="(i) => navigateTo(`/settings/emailaccounts/edit/${i.id}`)"
:on-select="(i) => navigateTo(`/settings/emailaccounts/edit/${i.id}`)"
:ui="{ divide: 'divide-gray-200 dark:divide-gray-800' }"
:empty-state="{ icon: 'i-heroicons-circle-stack-20-solid', label: 'Keine E-Mail Konten anzuzeigen' }"
:empty="{ icon: 'i-heroicons-circle-stack-20-solid', label: 'Keine E-Mail Konten anzuzeigen' }"
>
</UTable>
</template>

View File

@@ -33,13 +33,13 @@ const labelPrinterURI = ref("")
Etikettendrucker
</template>
<UFormGroup
<UFormField
label="IP-Adresse:"
>
<UInput
v-model="labelPrinterURI"
/>
</UFormGroup>
</UFormField>
<UButton
@click="setupPrinter"

View File

@@ -37,7 +37,7 @@ const isLight = computed({
:items="items"
class="h-100 p-5"
>
<template #item="{item}">
<template #content="{item}">
<UCard class="mt-5">
<div v-if="item.label === 'Profil'">
@@ -86,4 +86,4 @@ const isLight = computed({
<style scoped>
</style>
</style>

View File

@@ -168,7 +168,7 @@ setupPage()
}
]"
>
<template #item="{item}">
<template #content="{item}">
<div v-if="item.label === 'Dokubox'">
<UAlert
class="mt-5"
@@ -190,17 +190,17 @@ setupPage()
<div v-if="item.label === 'Rechnung & Kontakt'">
<UCard class="mt-5">
<UForm class="w-1/2">
<UFormGroup
<UFormField
label="Firmenname:"
>
<UInput v-model="businessInfo.name"/>
</UFormGroup>
<UFormGroup
</UFormField>
<UFormField
label="Straße + Hausnummer:"
>
<UInput v-model="businessInfo.street"/>
</UFormGroup>
<UFormGroup
</UFormField>
<UFormField
label="PLZ + Ort"
class="w-full"
>
@@ -208,41 +208,41 @@ setupPage()
<UInput v-model="businessInfo.zip"/>
<UInput v-model="businessInfo.city" class="flex-auto"/>
</InputGroup>
</UFormGroup>
</UFormField>
<UButton
class="mt-3"
@click="updateTenant({businessInfo: businessInfo})"
>
Speichern
</UButton>
<UFormGroup
<UFormField
label="Kontenrahmen:"
class="mt-6"
>
<USelectMenu
v-model="accountChart"
:options="accountChartOptions"
option-attribute="label"
value-attribute="value"
:items="accountChartOptions"
label-key="label"
value-key="value"
/>
</UFormGroup>
</UFormField>
<UButton
class="mt-3"
@click="updateTenant({accountChart: accountChart})"
>
Kontenrahmen speichern
</UButton>
<UFormGroup
<UFormField
label="USt-Auswertung:"
class="mt-6"
>
<USelectMenu
v-model="taxEvaluationPeriod"
:options="TAX_EVALUATION_PERIOD_OPTIONS"
option-attribute="label"
value-attribute="value"
:items="TAX_EVALUATION_PERIOD_OPTIONS"
label-key="label"
value-key="value"
/>
</UFormGroup>
</UFormField>
<UButton
class="mt-3"
@click="updateTenant({taxEvaluationPeriod: taxEvaluationPeriod})"

View File

@@ -163,7 +163,7 @@ const getDocLabel = (type) => {
:data="texttemplates"
:loading="loading"
v-model:expand="expand"
:empty-state="{ icon: 'i-heroicons-document-text', label: 'Keine Textvorlagen gefunden' }"
:empty="{ icon: 'i-heroicons-document-text', label: 'Keine Textvorlagen gefunden' }"
:columns="normalizeTableColumns([
{ key: 'name', label: 'Bezeichnung' },
{ key: 'documentType', label: 'Verwendung' },
@@ -172,33 +172,33 @@ const getDocLabel = (type) => {
{ key: 'actions', label: '' }
])"
>
<template #name-data="{ row }">
<span class="font-medium text-gray-900 dark:text-white">{{ row.name }}</span>
<template #name-cell="{ row }">
<span class="font-medium text-gray-900 dark:text-white">{{ row.original.name }}</span>
</template>
<template #documentType-data="{ row }">
<template #documentType-cell="{ row }">
<UBadge color="gray" variant="soft">
{{ getDocLabel(row.documentType) }}
{{ getDocLabel(row.original.documentType) }}
</UBadge>
</template>
<template #pos-data="{ row }">
<template #pos-cell="{ row }">
<div class="flex items-center gap-2">
<UIcon
:name="row.pos === 'startText' ? 'i-heroicons-bars-arrow-down' : 'i-heroicons-bars-arrow-up'"
:name="row.original.pos === 'startText' ? 'i-heroicons-bars-arrow-down' : 'i-heroicons-bars-arrow-up'"
class="w-4 h-4 text-gray-500"
/>
<span>{{ row.pos === 'startText' ? 'Einleitung' : 'Endtext' }}</span>
<span>{{ row.original.pos === 'startText' ? 'Einleitung' : 'Endtext' }}</span>
</div>
</template>
<template #default-data="{ row }">
<UIcon v-if="row.default" name="i-heroicons-check-circle-20-solid" class="text-green-500"/>
<template #default-cell="{ row }">
<UIcon v-if="row.original.default" name="i-heroicons-check-circle-20-solid" class="text-green-500"/>
<span v-else class="text-gray-400">-</span>
</template>
<template #actions-data="{ row }">
<UButton color="gray" variant="ghost" icon="i-heroicons-pencil-square" @click="openModal(row)"/>
<template #actions-cell="{ row }">
<UButton color="gray" variant="ghost" icon="i-heroicons-pencil-square" @click="openModal(row.original)"/>
</template>
<template #expand="{ row }">
@@ -206,7 +206,7 @@ const getDocLabel = (type) => {
<div class="mb-4">
<h4 class="text-sm font-bold uppercase text-gray-500 mb-1">Vorschau</h4>
<p class="text-gray-800 dark:text-gray-200 whitespace-pre-line p-3 bg-white dark:bg-gray-900 rounded border border-gray-200 dark:border-gray-700 text-sm">
{{ row.text }}
{{ row.original.text }}
</p>
</div>
@@ -237,25 +237,26 @@ const getDocLabel = (type) => {
</UDashboardPanelContent>
<UModal v-model:open="editTemplateModalOpen" :ui="{ width: 'sm:max-w-4xl' }">
<UCard>
<template #header>
<div class="flex justify-between items-center">
<h3 class="text-lg font-semibold">
{{ itemInfo.id ? 'Vorlage bearbeiten' : 'Neue Vorlage erstellen' }}
</h3>
<UButton color="gray" variant="ghost" icon="i-heroicons-x-mark" @click="editTemplateModalOpen = false"/>
</div>
</template>
<template #content>
<UCard>
<template #header>
<div class="flex justify-between items-center">
<h3 class="text-lg font-semibold">
{{ itemInfo.id ? 'Vorlage bearbeiten' : 'Neue Vorlage erstellen' }}
</h3>
<UButton color="gray" variant="ghost" icon="i-heroicons-x-mark" @click="editTemplateModalOpen = false"/>
</div>
</template>
<div class="grid grid-cols-1 lg:grid-cols-3 gap-6">
<div class="lg:col-span-2 space-y-4">
<UFormGroup label="Bezeichnung" required>
<UFormField label="Bezeichnung" required>
<UInput v-model="itemInfo.name" placeholder="z.B. Standard Angebotstext" icon="i-heroicons-tag"/>
</UFormGroup>
</UFormField>
<div class="grid grid-cols-2 gap-4">
<UFormGroup label="Dokumententyp" required>
<UFormField label="Dokumententyp" required>
<USelectMenu
v-model="itemInfo.documentType"
:options="Object.keys(dataStore.documentTypesForCreation || {})
@@ -264,9 +265,9 @@ const getDocLabel = (type) => {
option-attribute="label"
value-attribute="key"
/>
</UFormGroup>
</UFormField>
<UFormGroup label="Position" required>
<UFormField label="Position" required>
<USelectMenu
v-model="itemInfo.pos"
:options="[
@@ -276,10 +277,10 @@ const getDocLabel = (type) => {
option-attribute="label"
value-attribute="key"
/>
</UFormGroup>
</UFormField>
</div>
<UFormGroup label="Text Inhalt" required help="Klicken Sie rechts auf eine Variable, um sie einzufügen.">
<UFormField label="Text Inhalt" required help="Klicken Sie rechts auf eine Variable, um sie einzufügen.">
<UTextarea
ref="textareaRef"
v-model="itemInfo.text"
@@ -287,7 +288,7 @@ const getDocLabel = (type) => {
placeholder="Sehr geehrte Damen und Herren..."
class="font-mono text-sm"
/>
</UFormGroup>
</UFormField>
<UCheckbox v-model="itemInfo.default" label="Als Standard für diesen Typ verwenden"/>
</div>
@@ -342,34 +343,35 @@ const getDocLabel = (type) => {
</div>
<template #footer>
<div class="flex justify-end gap-3">
<UButton color="gray" variant="ghost" @click="editTemplateModalOpen = false">
Abbrechen
</UButton>
<template #footer>
<div class="flex justify-end gap-3">
<UButton color="gray" variant="ghost" @click="editTemplateModalOpen = false">
Abbrechen
</UButton>
<UButton
v-if="!itemInfo.id"
color="primary"
:loading="isSaving"
@click="handleCreate"
icon="i-heroicons-plus"
>
Erstellen
</UButton>
<UButton
v-if="!itemInfo.id"
color="primary"
:loading="isSaving"
@click="handleCreate"
icon="i-heroicons-plus"
>
Erstellen
</UButton>
<UButton
v-else
color="primary"
:loading="isSaving"
@click="handleUpdate"
icon="i-heroicons-check"
>
Speichern
</UButton>
</div>
</template>
</UCard>
<UButton
v-else
color="primary"
:loading="isSaving"
@click="handleUpdate"
icon="i-heroicons-check"
>
Speichern
</UButton>
</div>
</template>
</UCard>
</template>
</UModal>
</template>