diff --git a/backend/locale/en/LC_MESSAGES/django.mo b/backend/locale/en/LC_MESSAGES/django.mo
index c9e4361..56fa243 100644
Binary files a/backend/locale/en/LC_MESSAGES/django.mo and b/backend/locale/en/LC_MESSAGES/django.mo differ
diff --git a/backend/locale/en/LC_MESSAGES/django.po b/backend/locale/en/LC_MESSAGES/django.po
index 469ca79..ca8e780 100644
--- a/backend/locale/en/LC_MESSAGES/django.po
+++ b/backend/locale/en/LC_MESSAGES/django.po
@@ -2,14 +2,15 @@ msgid ""
msgstr ""
"Project-Id-Version: tubco-portal\n"
"Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2026-03-27 10:24+0000\n"
+"POT-Creation-Date: 2026-03-27 11:06+0000\n"
"PO-Revision-Date: 2026-03-24 00:00+0000\n"
"Language: en\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
-#: workflows/app_registry.py:35 workflows/models.py:482 workflows/models.py:563
+#: workflows/app_registry.py:35 workflows/models.py:482 workflows/models.py:521
+#: workflows/models.py:588
#: workflows/templates/workflows/onboarding_form.html:25
#: workflows/templates/workflows/requests_dashboard.html:68
#: workflows/templates/workflows/requests_dashboard.html:131
@@ -36,7 +37,7 @@ msgstr "Multi-step form"
msgid "E-Mail Routing"
msgstr "Email routing"
-#: workflows/app_registry.py:46 workflows/models.py:483 workflows/models.py:564
+#: workflows/app_registry.py:46 workflows/models.py:483 workflows/models.py:589
#: workflows/templates/workflows/requests_dashboard.html:78
#: workflows/templates/workflows/requests_dashboard.html:132
msgid "Offboarding"
@@ -126,6 +127,11 @@ msgstr ""
#: workflows/app_registry.py:142 workflows/app_registry.py:151
#: workflows/app_registry.py:160 workflows/app_registry.py:169
#: workflows/app_registry.py:178 workflows/app_registry.py:187
+#: workflows/templates/workflows/form_builder.html:82
+#: workflows/templates/workflows/form_builder.html:151
+#: workflows/templates/workflows/form_builder.html:259
+#: workflows/templates/workflows/form_builder.html:269
+#: workflows/templates/workflows/form_builder.html:344
#: workflows/templates/workflows/includes/app_header.html:57
msgid "Öffnen"
msgstr "Open"
@@ -219,7 +225,7 @@ msgstr "Manage scheduled welcome emails."
#: workflows/app_registry.py:158
#: workflows/templates/workflows/form_builder.html:4
-#: workflows/templates/workflows/form_builder.html:14
+#: workflows/templates/workflows/form_builder.html:16
msgid "Form Builder"
msgstr "Form Builder"
@@ -549,7 +555,7 @@ msgstr "Save offboarding request"
msgid "Backup erfolgreich"
msgstr "Submitted"
-#: workflows/forms.py:395 workflows/views.py:1348
+#: workflows/forms.py:395 workflows/views.py:1387
#, fuzzy
#| msgid "Fehlgeschlagen"
msgid "Backup fehlgeschlagen"
@@ -585,7 +591,7 @@ msgstr "Introduction"
msgid "Workflow"
msgstr "Workflow rules"
-#: workflows/forms.py:416 workflows/views.py:1505
+#: workflows/forms.py:416 workflows/views.py:1544
#, fuzzy
#| msgid "Welcome E-Mails"
msgid "Welcome E-Mail"
@@ -611,11 +617,11 @@ msgstr "Role:"
msgid "Dieser Benutzername ist bereits vergeben."
msgstr "This username is already taken."
-#: workflows/forms.py:498 workflows/views.py:1157
+#: workflows/forms.py:498 workflows/views.py:1196
msgid "Ungültige Rolle."
msgstr "Invalid role."
-#: workflows/forms.py:500 workflows/views.py:1160
+#: workflows/forms.py:500 workflows/views.py:1199
msgid "Nur Platform Owner dürfen diese Rolle vergeben."
msgstr ""
@@ -877,35 +883,35 @@ msgstr ""
msgid "Fehler"
msgstr ""
-#: workflows/models.py:308 workflows/views.py:601
+#: workflows/models.py:308 workflows/views.py:640
#, fuzzy
#| msgid "Gesamtbestand"
msgid "Gestartet"
msgstr "Total records"
-#: workflows/models.py:309 workflows/views.py:601
+#: workflows/models.py:309 workflows/views.py:640
#, fuzzy
#| msgid "Eingereicht"
msgid "Erfolgreich"
msgstr "Submitted"
-#: workflows/models.py:310 workflows/models.py:363 workflows/models.py:617
+#: workflows/models.py:310 workflows/models.py:363 workflows/models.py:642
#: workflows/templates/workflows/backup_recovery.html:102
#: workflows/templates/workflows/requests_dashboard.html:222
-#: workflows/templates/workflows/welcome_emails.html:108 workflows/views.py:427
-#: workflows/views.py:601
+#: workflows/templates/workflows/welcome_emails.html:108 workflows/views.py:436
+#: workflows/views.py:640
msgid "Fehlgeschlagen"
msgstr "Failed"
-#: workflows/models.py:360 workflows/views.py:424
+#: workflows/models.py:360 workflows/views.py:433
msgid "Eingereicht"
msgstr "Submitted"
-#: workflows/models.py:361 workflows/views.py:425
+#: workflows/models.py:361 workflows/views.py:434
msgid "In Bearbeitung"
msgstr "Processing"
-#: workflows/models.py:362 workflows/models.py:677 workflows/views.py:426
+#: workflows/models.py:362 workflows/models.py:702 workflows/views.py:435
msgid "Abgeschlossen"
msgstr "Completed"
@@ -959,169 +965,170 @@ msgstr ""
msgid "Automatisch"
msgstr ""
-#: workflows/models.py:476 workflows/views.py:119
+#: workflows/models.py:476 workflows/models.py:524 workflows/views.py:128
msgid "Stammdaten"
msgstr "Master data"
-#: workflows/models.py:477 workflows/views.py:120
+#: workflows/models.py:477 workflows/models.py:525 workflows/views.py:129
msgid "Vertrag"
msgstr "Contract"
-#: workflows/models.py:478 workflows/views.py:121
+#: workflows/models.py:478 workflows/models.py:526 workflows/views.py:130
msgid "IT-Setup"
msgstr "IT setup"
-#: workflows/models.py:479 workflows/views.py:122
+#: workflows/models.py:479 workflows/models.py:527 workflows/views.py:131
+#: workflows/views.py:566
msgid "Abschluss"
msgstr "Finish"
-#: workflows/models.py:521
+#: workflows/models.py:546
#, fuzzy
#| msgid "Onboarding"
msgid "Onboarding: IT"
msgstr "Onboarding"
-#: workflows/models.py:522
+#: workflows/models.py:547
#, fuzzy
#| msgid "Offboarding-Anfrage speichern"
msgid "Onboarding: Allgemeine Info"
msgstr "Save offboarding request"
-#: workflows/models.py:523
+#: workflows/models.py:548
#, fuzzy
#| msgid "Onboarding starten"
msgid "Onboarding: Visitenkarte"
msgstr "Start onboarding"
-#: workflows/models.py:524
+#: workflows/models.py:549
#, fuzzy
#| msgid "Onboarding"
msgid "Onboarding: HR Works"
msgstr "Onboarding"
-#: workflows/models.py:525
+#: workflows/models.py:550
#, fuzzy
#| msgid "Onboarding starten"
msgid "Onboarding: Schlüssel"
msgstr "Start onboarding"
-#: workflows/models.py:526
+#: workflows/models.py:551
msgid "Onboarding: Referenz Anfordernde Person"
msgstr ""
-#: workflows/models.py:527
+#: workflows/models.py:552
#, fuzzy
#| msgid "Welcome E-Mails"
msgid "Onboarding: Welcome E-Mail"
msgstr "Welcome Emails"
-#: workflows/models.py:528
+#: workflows/models.py:553
#, fuzzy
#| msgid "Offboarding"
msgid "Offboarding: IT"
msgstr "Offboarding"
-#: workflows/models.py:529
+#: workflows/models.py:554
#, fuzzy
#| msgid "Offboarding-Anfrage speichern"
msgid "Offboarding: Allgemeine Info"
msgstr "Save offboarding request"
-#: workflows/models.py:530
+#: workflows/models.py:555
#, fuzzy
#| msgid "Offboarding starten"
msgid "Offboarding: HR Works Deaktivierung"
msgstr "Start offboarding"
-#: workflows/models.py:531
+#: workflows/models.py:556
msgid "Offboarding: Referenz Anfordernde Person"
msgstr ""
-#: workflows/models.py:567
+#: workflows/models.py:592
msgid "Immer"
msgstr ""
-#: workflows/models.py:568 workflows/models.py:646
+#: workflows/models.py:593 workflows/models.py:671
msgid "Enthält"
msgstr ""
-#: workflows/models.py:569 workflows/models.py:647
+#: workflows/models.py:594 workflows/models.py:672
msgid "Ist gleich"
msgstr ""
-#: workflows/models.py:570
+#: workflows/models.py:595
msgid "Ist aktiv/Ja"
msgstr ""
-#: workflows/models.py:571
+#: workflows/models.py:596
#, fuzzy
#| msgid "inaktiv"
msgid "Ist inaktiv/Nein"
msgstr "inactive"
-#: workflows/models.py:613
+#: workflows/models.py:638
#: workflows/templates/workflows/welcome_emails.html:100
msgid "Geplant"
msgstr "Scheduled"
-#: workflows/models.py:614
+#: workflows/models.py:639
#: workflows/templates/workflows/welcome_emails.html:102
msgid "Pausiert"
msgstr "Paused"
-#: workflows/models.py:615
+#: workflows/models.py:640
#: workflows/templates/workflows/welcome_emails.html:104
msgid "Abgebrochen"
msgstr "Cancelled"
-#: workflows/models.py:616
+#: workflows/models.py:641
#: workflows/templates/workflows/welcome_emails.html:106
msgid "Gesendet"
msgstr "Sent"
-#: workflows/models.py:639 workflows/tasks.py:627
+#: workflows/models.py:664 workflows/tasks.py:627
msgid "Geräte und Arbeitsplatz"
msgstr "Devices and workplace"
-#: workflows/models.py:640 workflows/tasks.py:628
+#: workflows/models.py:665 workflows/tasks.py:628
msgid "Konten und Berechtigungen"
msgstr "Accounts and permissions"
-#: workflows/models.py:641 workflows/tasks.py:629
+#: workflows/models.py:666 workflows/tasks.py:629
msgid "Software und Tools"
msgstr "Software and tools"
-#: workflows/models.py:642 workflows/tasks.py:630
+#: workflows/models.py:667 workflows/tasks.py:630
msgid "Prozesse und Hinweise"
msgstr "Processes and notes"
-#: workflows/models.py:645
+#: workflows/models.py:670
msgid "Immer anzeigen"
msgstr "Always show"
-#: workflows/models.py:648
+#: workflows/models.py:673
msgid "Ist Ja / aktiv"
msgstr "Is yes / active"
-#: workflows/models.py:649
+#: workflows/models.py:674
msgid "Ist Nein / inaktiv"
msgstr "Is no / inactive"
-#: workflows/models.py:676
+#: workflows/models.py:701
msgid "Entwurf"
msgstr "Draft"
-#: workflows/models.py:696
+#: workflows/models.py:721
#, fuzzy
#| msgid "Nextcloud:"
msgid "Nextcloud"
msgstr "Nextcloud:"
-#: workflows/models.py:697
+#: workflows/models.py:722
msgid "S3"
msgstr ""
-#: workflows/models.py:698
+#: workflows/models.py:723
msgid "NFS"
msgstr ""
@@ -1518,7 +1525,7 @@ msgstr ""
#: workflows/templates/workflows/account_profile.html:262
#: workflows/templates/workflows/app_registry.html:35
#: workflows/templates/workflows/app_registry.html:84
-#: workflows/templates/workflows/form_builder.html:91
+#: workflows/templates/workflows/form_builder.html:308
#: workflows/templates/workflows/integrations_setup.html:263
#: workflows/templates/workflows/intro_builder.html:65
#: workflows/templates/workflows/trial_management.html:28
@@ -1707,7 +1714,7 @@ msgstr "Last updated"
#: workflows/templates/workflows/app_registry.html:4
#: workflows/templates/workflows/app_registry.html:103
-#: workflows/templates/workflows/form_builder.html:87
+#: workflows/templates/workflows/form_builder.html:304
#: workflows/templates/workflows/intro_builder.html:58
msgid "Sortierung"
msgstr "Sort order"
@@ -1838,6 +1845,7 @@ msgid "Platzierung"
msgstr "Sort order"
#: workflows/templates/workflows/app_registry.html:166
+#: workflows/templates/workflows/form_builder.html:36
#, fuzzy
#| msgid "Reihenfolge speichern"
msgid "Reihenfolge"
@@ -2193,8 +2201,8 @@ msgid "Backup-Bundle wirklich löschen?"
msgstr "Delete this backup bundle?"
#: workflows/templates/workflows/backup_recovery.html:133
-#: workflows/templates/workflows/form_builder.html:92
-#: workflows/templates/workflows/form_builder.html:107
+#: workflows/templates/workflows/form_builder.html:309
+#: workflows/templates/workflows/form_builder.html:324
#: workflows/templates/workflows/integrations_setup.html:265
#: workflows/templates/workflows/intro_builder.html:66
#: workflows/templates/workflows/intro_builder.html:102
@@ -2324,109 +2332,249 @@ msgid ""
msgstr ""
#: workflows/templates/workflows/form_builder.html:15
-msgid "Felder per Drag-and-Drop sortieren und pro Schritt gruppieren."
-msgstr "Sort fields by drag and drop and group them by step."
+msgid "Deployment Configuration"
+msgstr ""
-#: workflows/templates/workflows/form_builder.html:29
+#: workflows/templates/workflows/form_builder.html:27
msgid "Reihenfolge speichern"
msgstr "Save order"
-#: workflows/templates/workflows/form_builder.html:46
+#: workflows/templates/workflows/form_builder.html:35
+#, fuzzy
+#| msgid "Eingereicht"
+msgid "Bereiche"
+msgstr "Submitted"
+
+#: workflows/templates/workflows/form_builder.html:37
+#, fuzzy
+#| msgid "Regelname"
+msgid "Regeln"
+msgstr "Rule name"
+
+#: workflows/templates/workflows/form_builder.html:38
+#: workflows/templates/workflows/form_builder.html:257
+#, fuzzy
+#| msgid "Optionen verwalten"
+msgid "Optionen & Texte"
+msgstr "Manage options"
+
+#: workflows/templates/workflows/form_builder.html:43
+msgid "Fixe Kernfelder"
+msgstr ""
+
+#: workflows/templates/workflows/form_builder.html:47
+msgid "Konfigurierbar"
+msgstr ""
+
+#: workflows/templates/workflows/form_builder.html:51
+#, fuzzy
+#| msgid "Ausgeblendet"
+msgid "Aktuell ausgeblendet"
+msgstr "Hidden"
+
+#: workflows/templates/workflows/form_builder.html:56
+#, fuzzy
+#| msgid "Abschnitt"
+msgid "Versteckte Abschnitte"
+msgstr "Section"
+
+#: workflows/templates/workflows/form_builder.html:63
+msgid "Presets"
+msgstr ""
+
+#: workflows/templates/workflows/form_builder.html:80
+msgid "Live-Vorschau"
+msgstr ""
+
+#: workflows/templates/workflows/form_builder.html:91
+#: workflows/templates/workflows/form_builder.html:122
+#: workflows/templates/workflows/form_builder.html:203
+#, fuzzy, python-format
+#| msgid "Keine konfigurierten Felder in diesem Schritt."
+msgid "%(count)s Feld/Felder"
+msgstr "No configured fields in this step."
+
+#: workflows/templates/workflows/form_builder.html:97
+msgid "Keine sichtbaren Felder."
+msgstr ""
+
+#: workflows/templates/workflows/form_builder.html:110
+#, fuzzy
+#| msgid "Reihenfolge speichern"
+msgid "Struktur & Reihenfolge"
+msgstr "Save order"
+
+#: workflows/templates/workflows/form_builder.html:112
+#, fuzzy
+#| msgid "öffnen"
+msgid "Geöffnet"
+msgstr "open"
+
+#: workflows/templates/workflows/form_builder.html:132
+#: workflows/templates/workflows/form_builder.html:178
+#: workflows/templates/workflows/form_builder.html:227
msgid "Fix"
msgstr "Fixed"
-#: workflows/templates/workflows/form_builder.html:47
+#: workflows/templates/workflows/form_builder.html:133
+#: workflows/templates/workflows/form_builder.html:180
+#: workflows/templates/workflows/form_builder.html:229
msgid "Ausgeblendet"
msgstr "Hidden"
-#: workflows/templates/workflows/form_builder.html:48
+#: workflows/templates/workflows/form_builder.html:134
+#: workflows/templates/workflows/form_builder.html:218
+#: workflows/templates/workflows/form_builder.html:221
+#: workflows/templates/workflows/form_builder.html:231
msgid "Pflicht"
msgstr "Required"
-#: workflows/templates/workflows/form_builder.html:59
+#: workflows/templates/workflows/form_builder.html:149
+#, fuzzy
+#| msgid "Sicherheitsregeln"
+msgid "Sichtbarkeit & Regeln"
+msgstr "Safety rules"
+
+#: workflows/templates/workflows/form_builder.html:159
+#, fuzzy
+#| msgid "Abschnitt"
+msgid "Abschnitte steuern"
+msgstr "Section"
+
+#: workflows/templates/workflows/form_builder.html:168
+#, fuzzy, python-format
+#| msgid "Keine konfigurierten Felder in diesem Schritt."
+msgid "%(count)s Feld/Felder in diesem Abschnitt."
+msgstr "No configured fields in this step."
+
+#: workflows/templates/workflows/form_builder.html:179
+#: workflows/templates/workflows/form_builder.html:214
+msgid "Sichtbar"
+msgstr ""
+
+#: workflows/templates/workflows/form_builder.html:187
+#, fuzzy
+#| msgid "Regeln speichern"
+msgid "Abschnittsregeln speichern"
+msgstr "Save rules"
+
+#: workflows/templates/workflows/form_builder.html:194
+#, fuzzy
+#| msgid "Feldtexte verwalten"
+msgid "Feldregeln verwalten"
+msgstr "Manage field text"
+
+#: workflows/templates/workflows/form_builder.html:220
+#, fuzzy
+#| msgid "Standardsprache"
+msgid "Standard"
+msgstr "Default language"
+
+#: workflows/templates/workflows/form_builder.html:222
+#: workflows/templates/workflows/user_management.html:109
+msgid "Optional"
+msgstr "Optional"
+
+#: workflows/templates/workflows/form_builder.html:233
+msgid "Flexibel"
+msgstr ""
+
+#: workflows/templates/workflows/form_builder.html:238
+#, fuzzy
+#| msgid "Keine Feldkonfigurationen verfügbar."
+msgid "Keine Feldregeln verfügbar."
+msgstr "No field configurations available."
+
+#: workflows/templates/workflows/form_builder.html:245
+#, fuzzy
+#| msgid "Regeln speichern"
+msgid "Feldregeln speichern"
+msgstr "Save rules"
+
+#: workflows/templates/workflows/form_builder.html:268
msgid "Optionen verwalten"
msgstr "Manage options"
-#: workflows/templates/workflows/form_builder.html:62
+#: workflows/templates/workflows/form_builder.html:279
msgid "Kategorie"
msgstr "Category"
-#: workflows/templates/workflows/form_builder.html:75
-#: workflows/templates/workflows/form_builder.html:88
-#: workflows/templates/workflows/form_builder.html:133
+#: workflows/templates/workflows/form_builder.html:292
+#: workflows/templates/workflows/form_builder.html:305
+#: workflows/templates/workflows/form_builder.html:355
msgid "Label (DE)"
msgstr "Label (DE)"
-#: workflows/templates/workflows/form_builder.html:76
+#: workflows/templates/workflows/form_builder.html:293
msgid "Label (EN, optional)"
msgstr "Label (EN, optional)"
-#: workflows/templates/workflows/form_builder.html:77
+#: workflows/templates/workflows/form_builder.html:294
msgid "Technischer Wert (optional)"
msgstr "Technical value (optional)"
-#: workflows/templates/workflows/form_builder.html:78
+#: workflows/templates/workflows/form_builder.html:295
msgid "Option hinzufügen"
msgstr "Add option"
-#: workflows/templates/workflows/form_builder.html:89
-#: workflows/templates/workflows/form_builder.html:134
+#: workflows/templates/workflows/form_builder.html:306
+#: workflows/templates/workflows/form_builder.html:356
msgid "Label (EN)"
msgstr "Label (EN)"
-#: workflows/templates/workflows/form_builder.html:100
+#: workflows/templates/workflows/form_builder.html:317
msgid "Ziehen zum Sortieren"
msgstr "Drag to reorder"
-#: workflows/templates/workflows/form_builder.html:107
+#: workflows/templates/workflows/form_builder.html:324
msgid "Option wirklich löschen?"
msgstr "Delete this option?"
-#: workflows/templates/workflows/form_builder.html:111
+#: workflows/templates/workflows/form_builder.html:328
msgid "Keine Optionen in dieser Kategorie."
msgstr "No options in this category."
-#: workflows/templates/workflows/form_builder.html:117
+#: workflows/templates/workflows/form_builder.html:334
msgid "Optionen speichern"
msgstr "Save options"
-#: workflows/templates/workflows/form_builder.html:124
+#: workflows/templates/workflows/form_builder.html:343
msgid "Feldtexte verwalten"
msgstr "Manage field text"
-#: workflows/templates/workflows/form_builder.html:132
+#: workflows/templates/workflows/form_builder.html:354
msgid "Feld"
msgstr "Field"
-#: workflows/templates/workflows/form_builder.html:135
+#: workflows/templates/workflows/form_builder.html:357
msgid "Hilfetext (DE)"
msgstr "Help text (DE)"
-#: workflows/templates/workflows/form_builder.html:136
+#: workflows/templates/workflows/form_builder.html:358
msgid "Hilfetext (EN)"
msgstr "Help text (EN)"
-#: workflows/templates/workflows/form_builder.html:146
+#: workflows/templates/workflows/form_builder.html:372
msgid "Fallback: Standardlabel"
msgstr "Fallback: default label"
-#: workflows/templates/workflows/form_builder.html:147
+#: workflows/templates/workflows/form_builder.html:373
msgid "English label"
msgstr "English label"
-#: workflows/templates/workflows/form_builder.html:148
+#: workflows/templates/workflows/form_builder.html:374
msgid "Optionaler Hilfetext"
msgstr "Optional help text"
-#: workflows/templates/workflows/form_builder.html:149
+#: workflows/templates/workflows/form_builder.html:375
msgid "Optional English help text"
msgstr "Optional English help text"
-#: workflows/templates/workflows/form_builder.html:152
+#: workflows/templates/workflows/form_builder.html:378
msgid "Keine Feldkonfigurationen verfügbar."
msgstr "No field configurations available."
-#: workflows/templates/workflows/form_builder.html:158
+#: workflows/templates/workflows/form_builder.html:385
msgid "Feldtexte speichern"
msgstr "Save field text"
@@ -3061,7 +3209,7 @@ msgstr "Search"
msgid "Vorbefüllt aus:"
msgstr "Prefilled from:"
-#: workflows/templates/workflows/offboarding_form.html:64
+#: workflows/templates/workflows/offboarding_form.html:74
msgid "Offboarding-Anfrage speichern"
msgstr "Save offboarding request"
@@ -3203,7 +3351,7 @@ msgid "Dienstliche E-Mail"
msgstr "Work email"
#: workflows/templates/workflows/onboarding_intro_session.html:31
-#: workflows/views.py:1444
+#: workflows/views.py:1483
msgid "Vertragsbeginn"
msgstr "Contract start"
@@ -3849,10 +3997,6 @@ msgstr "Change roles, block access, or set a new password."
msgid "Sie selbst"
msgstr "You"
-#: workflows/templates/workflows/user_management.html:109
-msgid "Optional"
-msgstr "Optional"
-
#: workflows/templates/workflows/user_management.html:119
msgid "Reset-Link senden"
msgstr ""
@@ -4007,324 +4151,350 @@ msgstr "Resume"
msgid "Keine geplanten Welcome E-Mails vorhanden."
msgstr "No scheduled welcome emails available."
-#: workflows/views.py:119
+#: workflows/views.py:128
msgid "Person, Rolle, Abteilung"
msgstr "Person, role, department"
-#: workflows/views.py:120
+#: workflows/views.py:129
msgid "Beschäftigung und Termine"
msgstr "Employment and dates"
-#: workflows/views.py:121
+#: workflows/views.py:130
msgid "Geräte, Software und Zugänge"
msgstr "Devices, software, and access"
-#: workflows/views.py:122
+#: workflows/views.py:131
msgid "Notizen und Freigabe"
msgstr "Notes and approval"
-#: workflows/views.py:255
+#: workflows/views.py:264
#, fuzzy
#| msgid "Lokal gespeichert"
msgid "Profilbild gespeichert."
msgstr "Stored locally"
-#: workflows/views.py:257
+#: workflows/views.py:266
#, fuzzy
#| msgid "Passwort konnte nicht gespeichert werden"
msgid "Profilbild konnte nicht gespeichert werden."
msgstr "Password could not be saved"
-#: workflows/views.py:263
+#: workflows/views.py:272
#, fuzzy
#| msgid "Lokal gespeichert"
msgid "Profildaten gespeichert."
msgstr "Stored locally"
-#: workflows/views.py:265
+#: workflows/views.py:274
#, fuzzy
#| msgid "Passwort konnte nicht gespeichert werden"
msgid "Profildaten konnten nicht gespeichert werden."
msgstr "Password could not be saved"
-#: workflows/views.py:271
+#: workflows/views.py:280
#, fuzzy
#| msgid "Offboarding-Anfrage speichern"
msgid "Benachrichtigungseinstellungen gespeichert."
msgstr "Save offboarding request"
-#: workflows/views.py:273
+#: workflows/views.py:282
#, fuzzy
#| msgid "Passwort konnte nicht gespeichert werden"
msgid "Benachrichtigungseinstellungen konnten nicht gespeichert werden."
msgstr "Password could not be saved"
-#: workflows/views.py:282
+#: workflows/views.py:291
#, fuzzy
#| msgid "Deaktivieren"
msgid "TOTP wurde aktiviert."
msgstr "Disabled"
-#: workflows/views.py:284
+#: workflows/views.py:293
#, fuzzy
#| msgid "Passwort konnte nicht gespeichert werden"
msgid "TOTP konnte nicht aktiviert werden."
msgstr "Password could not be saved"
-#: workflows/views.py:291
+#: workflows/views.py:300
msgid "TOTP wurde deaktiviert."
msgstr ""
-#: workflows/views.py:293
+#: workflows/views.py:302
#, fuzzy
#| msgid "Passwort konnte nicht gespeichert werden"
msgid "TOTP konnte nicht deaktiviert werden."
msgstr "Password could not be saved"
-#: workflows/views.py:302
+#: workflows/views.py:311
msgid "Recovery-Codes wurden neu erzeugt."
msgstr ""
-#: workflows/views.py:304
+#: workflows/views.py:313
#, fuzzy
#| msgid "Passwort konnte nicht gespeichert werden"
msgid "Recovery-Codes konnten nicht neu erzeugt werden."
msgstr "Password could not be saved"
-#: workflows/views.py:353 workflows/views.py:1530 workflows/views.py:1535
+#: workflows/views.py:362 workflows/views.py:1569 workflows/views.py:1574
msgid "Sie haben keine Berechtigung für diese Aktion."
msgstr "You do not have permission for this action."
-#: workflows/views.py:434
+#: workflows/views.py:443
#, fuzzy
#| msgid "Vorgänge"
msgid "Vorgänge gelöscht"
msgstr "Requests"
-#: workflows/views.py:435
+#: workflows/views.py:444
msgid "Vorgang gelöscht"
msgstr ""
-#: workflows/views.py:436
+#: workflows/views.py:445
msgid "Vorgang erneut angestoßen"
msgstr ""
-#: workflows/views.py:437
+#: workflows/views.py:446
#, fuzzy
#| msgid "Einweisung"
msgid "Einweisungs-PDF erzeugt"
msgstr "Introduction"
-#: workflows/views.py:438
+#: workflows/views.py:447
#, fuzzy
#| msgid "Live-Protokoll erzeugen"
msgid "Live-Protokoll erzeugt"
msgstr "Generate live protocol"
-#: workflows/views.py:439
+#: workflows/views.py:448
#, fuzzy
#| msgid "Einweisung wurde zurückgesetzt."
msgid "Einweisung zurückgesetzt"
msgstr "Introduction was reset."
-#: workflows/views.py:440
+#: workflows/views.py:449
#, fuzzy
#| msgid "Einweisung wurde als Entwurf gespeichert."
msgid "Einweisung als Entwurf gespeichert"
msgstr "Introduction was saved as draft."
-#: workflows/views.py:441
+#: workflows/views.py:450
#, fuzzy
#| msgid "Einweisung wurde als abgeschlossen gespeichert."
msgid "Einweisung abgeschlossen"
msgstr "Introduction was saved as completed."
-#: workflows/views.py:442
+#: workflows/views.py:451
msgid "Formularoption gelöscht"
msgstr ""
-#: workflows/views.py:443
+#: workflows/views.py:452
#, fuzzy
#| msgid "Optionen speichern"
msgid "Formularoptionen gespeichert"
msgstr "Save options"
-#: workflows/views.py:444
+#: workflows/views.py:453
#, fuzzy
#| msgid "Feldtexte speichern"
msgid "Feldtexte gespeichert"
msgstr "Save field text"
-#: workflows/views.py:445
+#: workflows/views.py:454
#, fuzzy
#| msgid "Offboarding-Anfrage speichern"
msgid "Formularlayout gespeichert"
msgstr "Save offboarding request"
-#: workflows/views.py:446
+#: workflows/views.py:455
msgid "Einweisungs-Checkpunkt gelöscht"
msgstr ""
-#: workflows/views.py:447
+#: workflows/views.py:456
msgid "Einweisungs-Checkpunkt hinzugefügt"
msgstr ""
-#: workflows/views.py:448
+#: workflows/views.py:457
#, fuzzy
#| msgid "Checkliste speichern"
msgid "Einweisungs-Checkliste gespeichert"
msgstr "Save checklist"
-#: workflows/views.py:449
+#: workflows/views.py:458
#, fuzzy
#| msgid "Welcome E-Mails"
msgid "Welcome E-Mail sofort ausgelöst"
msgstr "Welcome Emails"
-#: workflows/views.py:450
+#: workflows/views.py:459
#, fuzzy
#| msgid "Welcome-Einstellungen speichern"
msgid "Welcome E-Mail Einstellungen gespeichert"
msgstr "Save welcome settings"
-#: workflows/views.py:451
+#: workflows/views.py:460
msgid "Welcome E-Mail Sammelaktion ausgeführt"
msgstr ""
-#: workflows/views.py:452
+#: workflows/views.py:461
#, fuzzy
#| msgid "Welcome E-Mails"
msgid "Welcome E-Mail pausiert"
msgstr "Welcome Emails"
-#: workflows/views.py:453
+#: workflows/views.py:462
#, fuzzy
#| msgid "Welcome E-Mails"
msgid "Welcome E-Mail fortgesetzt"
msgstr "Welcome Emails"
-#: workflows/views.py:454
+#: workflows/views.py:463
#, fuzzy
#| msgid "Welcome E-Mails"
msgid "Welcome E-Mail abgebrochen"
msgstr "Welcome Emails"
-#: workflows/views.py:455
+#: workflows/views.py:464
#, fuzzy
#| msgid "SMTP-Test"
msgid "SMTP-Test gesendet"
msgstr "SMTP test"
-#: workflows/views.py:456
+#: workflows/views.py:465
#, fuzzy
#| msgid "Nextcloud-Test"
msgid "Nextcloud-Testupload ausgeführt"
msgstr "Nextcloud test"
-#: workflows/views.py:457
+#: workflows/views.py:466
#, fuzzy
#| msgid "Nextcloud schalten"
msgid "Nextcloud-Modus umgeschaltet"
msgstr "Toggle Nextcloud"
-#: workflows/views.py:458
+#: workflows/views.py:467
msgid "E-Mail-Modus umgeschaltet"
msgstr ""
-#: workflows/views.py:459
+#: workflows/views.py:468
#, fuzzy
#| msgid "Integrationen Setup"
msgid "Integrationen gespeichert"
msgstr "Integrations Setup"
-#: workflows/views.py:460
+#: workflows/views.py:469
#, fuzzy
#| msgid "Welcome-Einstellungen speichern"
msgid "Nextcloud-Einstellungen gespeichert"
msgstr "Save welcome settings"
-#: workflows/views.py:461
+#: workflows/views.py:470
#, fuzzy
#| msgid "Welcome-Einstellungen speichern"
msgid "Mail-Einstellungen gespeichert"
msgstr "Save welcome settings"
-#: workflows/views.py:462
+#: workflows/views.py:471
#, fuzzy
#| msgid "E-Mail Routing & Vorlagen speichern"
msgid "E-Mail-Routing gespeichert"
msgstr "Save email routing & templates"
-#: workflows/views.py:463
+#: workflows/views.py:472
#, fuzzy
#| msgid "Offboarding-Anfrage speichern"
msgid "Benachrichtigungsregeln gespeichert"
msgstr "Save offboarding request"
-#: workflows/views.py:464
+#: workflows/views.py:473
#, fuzzy
#| msgid "Anfrage gespeichert"
msgid "Benutzer erstellt"
msgstr "Request saved"
-#: workflows/views.py:465
+#: workflows/views.py:474
msgid "Benutzer aktualisiert"
msgstr ""
-#: workflows/views.py:466
+#: workflows/views.py:475
msgid "Passwort-Reset-Link versendet"
msgstr ""
-#: workflows/views.py:467
+#: workflows/views.py:476
#, fuzzy
#| msgid "Benutzerübersicht"
msgid "Benutzer gelöscht"
msgstr "User overview"
-#: workflows/views.py:468
+#: workflows/views.py:477
#, fuzzy
#| msgid "Anfrage gespeichert"
msgid "Backup erstellt"
msgstr "Request saved"
-#: workflows/views.py:469
+#: workflows/views.py:478
msgid "Backup verifiziert"
msgstr ""
-#: workflows/views.py:470
+#: workflows/views.py:479
#, fuzzy
#| msgid "Anfrage gespeichert"
msgid "Backup gelöscht"
msgstr "Request saved"
-#: workflows/views.py:471
+#: workflows/views.py:480
#, fuzzy
#| msgid "Welcome-Einstellungen speichern"
msgid "Backup-Einstellungen gespeichert"
msgstr "Save welcome settings"
-#: workflows/views.py:472
+#: workflows/views.py:481
#, fuzzy
#| msgid "Anfrage gespeichert"
msgid "App-Registry gespeichert"
msgstr "Request saved"
-#: workflows/views.py:644
+#: workflows/views.py:564
+#, fuzzy
+#| msgid "Mitarbeiter"
+msgid "Mitarbeitende"
+msgstr "Staff"
+
+#: workflows/views.py:564
+#, fuzzy
+#| msgid "Person, Rolle, Abteilung"
+msgid "Person, Rolle und Bereich"
+msgstr "Person, role, department"
+
+#: workflows/views.py:565
+msgid "Austritt"
+msgstr ""
+
+#: workflows/views.py:565
+msgid "Letzter Arbeitstag"
+msgstr ""
+
+#: workflows/views.py:566
+#, fuzzy
+#| msgid "Einweisung wurde als abgeschlossen gespeichert."
+msgid "Hinweise und Abschlussnotizen"
+msgstr "Introduction was saved as completed."
+
+#: workflows/views.py:683
#, fuzzy
#| msgid "Anfrage gespeichert"
msgid "App-Registry gespeichert."
msgstr "Request saved"
-#: workflows/views.py:743
+#: workflows/views.py:782
msgid "Für diesen Benutzer ist keine E-Mail-Adresse hinterlegt."
msgstr ""
-#: workflows/views.py:752
+#: workflows/views.py:791
#, python-format
msgid "Zugangseinladung für %(username)s"
msgstr ""
-#: workflows/views.py:754
+#: workflows/views.py:793
#, python-format
msgid ""
"Hallo %(name)s,\n"
@@ -4337,12 +4507,12 @@ msgid ""
"Ihrem Administrator."
msgstr ""
-#: workflows/views.py:765
+#: workflows/views.py:804
#, python-format
msgid "Passwort zurücksetzen für %(username)s"
msgstr ""
-#: workflows/views.py:767
+#: workflows/views.py:806
#, python-format
msgid ""
"Hallo %(name)s,\n"
@@ -4355,7 +4525,7 @@ msgid ""
"ignorieren."
msgstr ""
-#: workflows/views.py:818
+#: workflows/views.py:857
#, fuzzy
#| msgid ""
#| "Benutzer konnte nicht erstellt werden. Bitte prüfen Sie die Eingaben."
@@ -4363,69 +4533,69 @@ msgid ""
"Branding konnte nicht gespeichert werden. Bitte prüfen Sie die Eingaben."
msgstr "User could not be created. Please check the input."
-#: workflows/views.py:846
+#: workflows/views.py:885
#, fuzzy
#| msgid "Offboarding-Anfrage speichern"
msgid "Portal-Branding wurde gespeichert."
msgstr "Save offboarding request"
-#: workflows/views.py:863
+#: workflows/views.py:902
msgid "Identität"
msgstr ""
-#: workflows/views.py:864
+#: workflows/views.py:903
msgid "Titel, Firmenname und zentrale Spracheinstellungen."
msgstr ""
-#: workflows/views.py:868
+#: workflows/views.py:907
msgid ""
"Wird für E-Mail-Vorschläge und Domain-bezogene Standardtexte verwendet, z. "
"B. workdock.de."
msgstr ""
-#: workflows/views.py:873
+#: workflows/views.py:912
msgid "Farben & Erscheinungsbild"
msgstr ""
-#: workflows/views.py:874
+#: workflows/views.py:913
msgid "Zentrale visuelle Markenwerte und Browser-Icon."
msgstr ""
-#: workflows/views.py:878
+#: workflows/views.py:917
msgid "Erlaubte Formate: SVG, PNG, JPG, JPEG, WEBP. Maximal 5 MB."
msgstr ""
-#: workflows/views.py:879
+#: workflows/views.py:918
msgid "Erlaubte Formate: ICO, PNG, SVG, WEBP. Maximal 2 MB."
msgstr ""
-#: workflows/views.py:884
+#: workflows/views.py:923
#, fuzzy
#| msgid "Produktion"
msgid "Kommunikation"
msgstr "Production"
-#: workflows/views.py:885
+#: workflows/views.py:924
msgid "Absender, Support und PDF-Branding für ausgehende Kommunikation."
msgstr ""
-#: workflows/views.py:889
+#: workflows/views.py:928
msgid "Wird für ausgehende System-E-Mails als Anzeigename verwendet."
msgstr ""
-#: workflows/views.py:890
+#: workflows/views.py:929
msgid "Erlaubtes Format: PDF. Maximal 10 MB."
msgstr ""
-#: workflows/views.py:895
+#: workflows/views.py:934
msgid "Footer & Rechtliches"
msgstr ""
-#: workflows/views.py:896
+#: workflows/views.py:935
msgid "Gemeinsame Footer-Texte und rechtliche Hinweise für die Shell."
msgstr ""
-#: workflows/views.py:950
+#: workflows/views.py:989
#, fuzzy
#| msgid ""
#| "Benutzer konnte nicht erstellt werden. Bitte prüfen Sie die Eingaben."
@@ -4434,53 +4604,53 @@ msgid ""
"Eingaben."
msgstr "User could not be created. Please check the input."
-#: workflows/views.py:979
+#: workflows/views.py:1018
#, fuzzy
#| msgid "Offboarding-Anfrage speichern"
msgid "Firmenkonfiguration wurde gespeichert."
msgstr "Save offboarding request"
-#: workflows/views.py:996
+#: workflows/views.py:1035
#, fuzzy
#| msgid "Firmenname"
msgid "Firmenprofil"
msgstr "Company name"
-#: workflows/views.py:997
+#: workflows/views.py:1036
msgid "Rechtlicher Name und zentrale Stammdaten der Firma."
msgstr ""
-#: workflows/views.py:1002
+#: workflows/views.py:1041
msgid "Adresse & Register"
msgstr ""
-#: workflows/views.py:1003
+#: workflows/views.py:1042
msgid "Anschrift sowie optionale Register- und Steuerangaben."
msgstr ""
-#: workflows/views.py:1008
+#: workflows/views.py:1047
msgid "Kontaktpunkte"
msgstr ""
-#: workflows/views.py:1009
+#: workflows/views.py:1048
msgid "Zentrale Ansprechpartner für HR, IT und Operations."
msgstr ""
-#: workflows/views.py:1014
+#: workflows/views.py:1053
msgid "Recht & Öffentlichkeit"
msgstr ""
-#: workflows/views.py:1015
+#: workflows/views.py:1054
msgid "Öffentliche Links für Website, Impressum und Datenschutz."
msgstr ""
-#: workflows/views.py:1017
+#: workflows/views.py:1056
msgid ""
"Diese Links können später im Portal-Footer oder in öffentlichen Seiten "
"verwendet werden."
msgstr ""
-#: workflows/views.py:1057
+#: workflows/views.py:1096
#, fuzzy
#| msgid ""
#| "Benutzer konnte nicht erstellt werden. Bitte prüfen Sie die Eingaben."
@@ -4489,54 +4659,54 @@ msgid ""
"Eingaben."
msgstr "Trial configuration could not be saved. Please check the input."
-#: workflows/views.py:1089
+#: workflows/views.py:1128
#, fuzzy
#| msgid "Trial abgelaufen"
msgid "Trial ist abgelaufen"
msgstr "Trial expired"
-#: workflows/views.py:1090
+#: workflows/views.py:1129
msgid ""
"Der Trial-Zeitraum ist überschritten. Nicht-Platform-Owner werden jetzt "
"blockiert."
msgstr ""
-#: workflows/views.py:1098
+#: workflows/views.py:1137
msgid "Trial läuft bald ab"
msgstr ""
-#: workflows/views.py:1099
+#: workflows/views.py:1138
#, python-format
msgid "Der Trial endet am %(date)s."
msgstr ""
-#: workflows/views.py:1107
+#: workflows/views.py:1146
#, fuzzy
#| msgid "Trial-Modus"
msgid "Trial-Modus deaktiviert"
msgstr "Trial mode"
-#: workflows/views.py:1108
+#: workflows/views.py:1147
#, fuzzy
#| msgid "Nextcloud schalten"
msgid "Der Trial-Modus wurde ausgeschaltet."
msgstr "Toggle Nextcloud"
-#: workflows/views.py:1113
+#: workflows/views.py:1152
msgid "Trial-Konfiguration wurde gespeichert."
msgstr "Trial configuration was saved."
-#: workflows/views.py:1130
+#: workflows/views.py:1169
msgid "Benutzer konnte nicht erstellt werden. Bitte prüfen Sie die Eingaben."
msgstr "User could not be created. Please check the input."
-#: workflows/views.py:1143
+#: workflows/views.py:1182
#, fuzzy, python-format
#| msgid "Benutzer wurde erstellt: %(username)s"
msgid "Benutzer wurde erstellt und eingeladen: %(username)s"
msgstr "User created: %(username)s"
-#: workflows/views.py:1165
+#: workflows/views.py:1204
#, fuzzy
#| msgid ""
#| "Der aktuell angemeldete Super Admin kann sich hier nicht selbst sperren "
@@ -4547,14 +4717,14 @@ msgid ""
msgstr ""
"The currently signed-in super admin cannot lock or downgrade themselves here."
-#: workflows/views.py:1168
+#: workflows/views.py:1207
msgid ""
"Der aktuell angemeldete Super Admin kann sich hier nicht selbst sperren oder "
"herabstufen."
msgstr ""
"The currently signed-in super admin cannot lock or downgrade themselves here."
-#: workflows/views.py:1171
+#: workflows/views.py:1210
#, fuzzy
#| msgid ""
#| "Der aktuell angemeldete Super Admin kann sich hier nicht selbst sperren "
@@ -4565,7 +4735,7 @@ msgid ""
msgstr ""
"The currently signed-in super admin cannot lock or downgrade themselves here."
-#: workflows/views.py:1174
+#: workflows/views.py:1213
#, fuzzy
#| msgid ""
#| "Der aktuell angemeldete Super Admin kann sich hier nicht selbst sperren "
@@ -4576,18 +4746,18 @@ msgid ""
msgstr ""
"The currently signed-in super admin cannot lock or downgrade themselves here."
-#: workflows/views.py:1191
+#: workflows/views.py:1230
#, python-format
msgid "Benutzer wurde aktualisiert: %(username)s"
msgstr "User updated: %(username)s"
-#: workflows/views.py:1213
+#: workflows/views.py:1252
#, fuzzy, python-format
#| msgid "Benutzer wurde erstellt: %(username)s"
msgid "Passwort-Reset-Link wurde versendet: %(username)s"
msgstr "User created: %(username)s"
-#: workflows/views.py:1225
+#: workflows/views.py:1264
#, fuzzy
#| msgid ""
#| "Der aktuell angemeldete Super Admin kann sich hier nicht selbst sperren "
@@ -4597,7 +4767,7 @@ msgid ""
msgstr ""
"The currently signed-in super admin cannot lock or downgrade themselves here."
-#: workflows/views.py:1228
+#: workflows/views.py:1267
#, fuzzy
#| msgid ""
#| "Der aktuell angemeldete Super Admin kann sich hier nicht selbst sperren "
@@ -4607,7 +4777,7 @@ msgid ""
msgstr ""
"The currently signed-in super admin cannot lock or downgrade themselves here."
-#: workflows/views.py:1231
+#: workflows/views.py:1270
#, fuzzy
#| msgid ""
#| "Der aktuell angemeldete Super Admin kann sich hier nicht selbst sperren "
@@ -4616,7 +4786,7 @@ msgid "Der letzte aktive Platform Owner kann nicht gelöscht werden."
msgstr ""
"The currently signed-in super admin cannot lock or downgrade themselves here."
-#: workflows/views.py:1234
+#: workflows/views.py:1273
#, fuzzy
#| msgid ""
#| "Der aktuell angemeldete Super Admin kann sich hier nicht selbst sperren "
@@ -4625,192 +4795,195 @@ msgid "Der letzte aktive Super Admin kann nicht gelöscht werden."
msgstr ""
"The currently signed-in super admin cannot lock or downgrade themselves here."
-#: workflows/views.py:1247
+#: workflows/views.py:1286
#, fuzzy, python-format
#| msgid "Benutzer wurde erstellt: %(username)s"
msgid "Benutzer wurde gelöscht: %(username)s"
msgstr "User created: %(username)s"
-#: workflows/views.py:1338
+#: workflows/views.py:1377
#, fuzzy, python-format
#| msgid "Anfrage gespeichert"
msgid "Backup erstellt: %(name)s"
msgstr "Request saved"
-#: workflows/views.py:1339
+#: workflows/views.py:1378
#, fuzzy
#| msgid "Offboarding-Anfrage speichern"
msgid "Das Backup-Bundle wurde erfolgreich erstellt."
msgstr "Save offboarding request"
-#: workflows/views.py:1344
+#: workflows/views.py:1383
#, python-format
msgid "Backup wurde erstellt: %(name)s"
msgstr ""
-#: workflows/views.py:1354
+#: workflows/views.py:1393
#, python-format
msgid "Backup konnte nicht erstellt werden: %(error)s"
msgstr ""
-#: workflows/views.py:1372
+#: workflows/views.py:1411
#, fuzzy, python-format
#| msgid "Backup wird verifiziert"
msgid "Backup verifiziert: %(name)s"
msgstr "Backup is being verified"
-#: workflows/views.py:1373
+#: workflows/views.py:1412
#, fuzzy
#| msgid "Backup wird verifiziert"
msgid "Das Backup wurde erfolgreich verifiziert."
msgstr "Backup is being verified"
-#: workflows/views.py:1378
+#: workflows/views.py:1417
#, python-format
msgid "Backup wurde verifiziert: %(name)s"
msgstr ""
-#: workflows/views.py:1382
+#: workflows/views.py:1421
#, fuzzy
#| msgid "Fehlgeschlagen"
msgid "Backup-Verifikation fehlgeschlagen"
msgstr "Failed"
-#: workflows/views.py:1388
+#: workflows/views.py:1427
#, python-format
msgid "Backup-Verifikation fehlgeschlagen: %(error)s"
msgstr ""
-#: workflows/views.py:1404
+#: workflows/views.py:1443
#, python-format
msgid "Backup wurde gelöscht: %(name)s"
msgstr ""
-#: workflows/views.py:1406
+#: workflows/views.py:1445
#, python-format
msgid "Backup konnte nicht gelöscht werden: %(error)s"
msgstr ""
-#: workflows/views.py:1432
+#: workflows/views.py:1471
#, fuzzy
#| msgid "Anfrage gespeichert"
msgid "Anfrage erstellt"
msgstr "Request saved"
-#: workflows/views.py:1434
+#: workflows/views.py:1473
#, fuzzy, python-format
#| msgid "Sitzungsstatus"
msgid "Status: %(status)s"
msgstr "Session status"
-#: workflows/views.py:1446
+#: workflows/views.py:1485
#, fuzzy
#| msgid "Geplant für"
msgid "Geplanter Start"
msgstr "Scheduled for"
-#: workflows/views.py:1456
+#: workflows/views.py:1495
msgid "Geräteübergabe / Hardware-Abholung"
msgstr ""
-#: workflows/views.py:1458
+#: workflows/views.py:1497
msgid "Geplanter Hardware-Termin"
msgstr ""
-#: workflows/views.py:1467
+#: workflows/views.py:1506
#, fuzzy
#| msgid "Noch nicht verfügbar"
msgid "PDF verfügbar"
msgstr "Not available yet"
-#: workflows/views.py:1493
+#: workflows/views.py:1532
#, fuzzy
#| msgid "Einweisung"
msgid "Einweisungssitzung"
msgstr "Introduction"
-#: workflows/views.py:1544
+#: workflows/views.py:1583
msgid "Keine Einträge ausgewählt."
msgstr "No entries selected."
-#: workflows/views.py:1587
+#: workflows/views.py:1626
#, python-format
msgid "%(count)s Eintrag/Einträge gelöscht."
msgstr "%(count)s entry/entries deleted."
-#: workflows/views.py:1589
+#: workflows/views.py:1628
#, python-format
msgid "%(count)s Auswahl(en) konnten nicht verarbeitet werden."
msgstr "%(count)s selection(s) could not be processed."
-#: workflows/views.py:1591
+#: workflows/views.py:1630
msgid "Keine passenden Einträge gefunden."
msgstr "No matching entries found."
-#: workflows/views.py:1819
+#: workflows/views.py:1863
msgid "Einweisungs- und Übergabeprotokoll wurde erzeugt."
msgstr "Introduction and handover protocol was generated."
-#: workflows/views.py:1836
+#: workflows/views.py:1880
msgid "Einweisungsprotokoll aus Live-Status wurde erzeugt."
msgstr "Introduction protocol from live status was generated."
-#: workflows/views.py:1865
+#: workflows/views.py:1909
msgid "Einweisung wurde zurückgesetzt."
msgstr "Introduction was reset."
-#: workflows/views.py:1879
+#: workflows/views.py:1923
msgid "Einweisung wurde als abgeschlossen gespeichert."
msgstr "Introduction was saved as completed."
-#: workflows/views.py:1892
+#: workflows/views.py:1936
msgid "Einweisung wurde als Entwurf gespeichert."
msgstr "Introduction was saved as draft."
-#: workflows/views.py:2677
+#: workflows/views.py:2907
#, fuzzy
#| msgid "SMTP-Test starten"
msgid "SMTP-Test erfolgreich"
msgstr "Run SMTP test"
-#: workflows/views.py:2678
+#: workflows/views.py:2908
#, fuzzy
#| msgid "Offboarding-Anfrage speichern"
msgid "Die SMTP-Testmail wurde erfolgreich gesendet."
msgstr "Save offboarding request"
-#: workflows/views.py:2687
+#: workflows/views.py:2917
#, fuzzy
#| msgid "SMTP-Test"
msgid "SMTP-Test fehlgeschlagen"
msgstr "SMTP test"
-#: workflows/views.py:2693
+#: workflows/views.py:2923
#, fuzzy, python-format
#| msgid "Passwort konnte nicht gespeichert werden"
msgid "SMTP-Testmail konnte nicht gesendet werden: %(error)s"
msgstr "Password could not be saved"
-#: workflows/views.py:2718
+#: workflows/views.py:2948
#, fuzzy
#| msgid "Nextcloud-Test starten"
msgid "Nextcloud-Test erfolgreich"
msgstr "Run Nextcloud test"
-#: workflows/views.py:2719
+#: workflows/views.py:2949
msgid "Der Testupload nach Nextcloud war erfolgreich."
msgstr ""
-#: workflows/views.py:2729 workflows/views.py:2739
+#: workflows/views.py:2959 workflows/views.py:2969
#, fuzzy
#| msgid "Nextcloud-Test starten"
msgid "Nextcloud-Test fehlgeschlagen"
msgstr "Run Nextcloud test"
-#: workflows/views.py:2730
+#: workflows/views.py:2960
msgid "Der Testupload nach Nextcloud ist fehlgeschlagen."
msgstr ""
+#~ msgid "Felder per Drag-and-Drop sortieren und pro Schritt gruppieren."
+#~ msgstr "Sort fields by drag and drop and group them by step."
+
#~ msgid "Direkte Aktionen für Ihr Workdock-Konto."
#~ msgstr "Direct actions for your Workdock account."
diff --git a/backend/workflows/form_builder.py b/backend/workflows/form_builder.py
index d7a03cf..a366a38 100644
--- a/backend/workflows/form_builder.py
+++ b/backend/workflows/form_builder.py
@@ -1,7 +1,7 @@
from collections import OrderedDict
from django.utils.translation import get_language
-from .models import FormFieldConfig
+from .models import FormFieldConfig, FormSectionConfig
DEFAULT_FIELD_ORDER = {
@@ -58,18 +58,29 @@ DEFAULT_FIELD_ORDER = {
}
ONBOARDING_PAGE_ORDER = ['stammdaten', 'vertrag', 'itsetup', 'abschluss']
+OFFBOARDING_PAGE_ORDER = ['mitarbeitende', 'austritt', 'abschluss']
ONBOARDING_PAGE_LABELS = {
'stammdaten': '1. Stammdaten',
'vertrag': '2. Vertrag',
'itsetup': '3. IT-Setup',
'abschluss': '4. Abschluss',
}
+OFFBOARDING_PAGE_LABELS = {
+ 'mitarbeitende': '1. Mitarbeitende',
+ 'austritt': '2. Austritt',
+ 'abschluss': '3. Abschluss',
+}
LOCKED_FIELD_RULES = {
'onboarding': {'full_name', 'work_email', 'contract_start', 'agreement_confirm'},
'offboarding': {'full_name', 'work_email', 'last_working_day'},
}
+LOCKED_SECTION_RULES = {
+ 'onboarding': {'stammdaten', 'vertrag', 'abschluss'},
+ 'offboarding': {'mitarbeitende', 'austritt'},
+}
+
ONBOARDING_DEFAULT_PAGE = {
'first_name': 'stammdaten',
'last_name': 'stammdaten',
@@ -112,6 +123,38 @@ ONBOARDING_DEFAULT_PAGE = {
'onboarded_by_email': 'abschluss',
'agreement_confirm': 'abschluss',
}
+OFFBOARDING_DEFAULT_PAGE = {
+ 'full_name': 'mitarbeitende',
+ 'work_email': 'mitarbeitende',
+ 'department': 'mitarbeitende',
+ 'job_title': 'mitarbeitende',
+ 'last_working_day': 'austritt',
+ 'notes': 'abschluss',
+}
+
+
+def get_section_order(form_type: str) -> list[str]:
+ if form_type == 'onboarding':
+ return ONBOARDING_PAGE_ORDER
+ if form_type == 'offboarding':
+ return OFFBOARDING_PAGE_ORDER
+ return []
+
+
+def get_section_labels(form_type: str) -> dict[str, str]:
+ if form_type == 'onboarding':
+ return ONBOARDING_PAGE_LABELS
+ if form_type == 'offboarding':
+ return OFFBOARDING_PAGE_LABELS
+ return {}
+
+
+def get_default_page_map(form_type: str) -> dict[str, str]:
+ if form_type == 'onboarding':
+ return ONBOARDING_DEFAULT_PAGE
+ if form_type == 'offboarding':
+ return OFFBOARDING_DEFAULT_PAGE
+ return {}
def _default_sort(form_type: str, field_name: str) -> int:
@@ -134,7 +177,7 @@ def _ensure_configs(form_type: str, field_names: list[str]) -> dict[str, FormFie
form_type=form_type,
field_name=name,
sort_order=_default_sort(form_type, name),
- page_key=ONBOARDING_DEFAULT_PAGE.get(name, '') if form_type == 'onboarding' else '',
+ page_key=get_default_page_map(form_type).get(name, ''),
)
for name in missing_names
],
@@ -151,10 +194,34 @@ def ensure_form_field_configs(form_type: str, field_names: list[str]) -> dict[st
return _ensure_configs(form_type, field_names)
+def ensure_form_section_configs(form_type: str) -> dict[str, FormSectionConfig]:
+ section_order = get_section_order(form_type)
+ if not section_order:
+ return {}
+ existing = {
+ cfg.section_key: cfg
+ for cfg in FormSectionConfig.objects.filter(form_type=form_type)
+ }
+ missing = [key for key in section_order if key not in existing]
+ if missing:
+ FormSectionConfig.objects.bulk_create(
+ [FormSectionConfig(form_type=form_type, section_key=key, is_visible=True) for key in missing],
+ ignore_conflicts=True,
+ )
+ existing = {
+ cfg.section_key: cfg
+ for cfg in FormSectionConfig.objects.filter(form_type=form_type)
+ }
+ return existing
+
+
def apply_form_field_config(form_type: str, form) -> None:
field_names = list(form.fields.keys())
configs = _ensure_configs(form_type, field_names)
+ section_configs = ensure_form_section_configs(form_type)
locked = LOCKED_FIELD_RULES.get(form_type, set())
+ locked_sections = LOCKED_SECTION_RULES.get(form_type, set())
+ default_page_map = get_default_page_map(form_type)
language_code = get_language()
for field_name, field in list(form.fields.items()):
@@ -173,7 +240,14 @@ def apply_form_field_config(form_type: str, form) -> None:
if field_name not in locked and cfg.is_required is not None:
field.required = cfg.is_required
- if field_name not in locked and not cfg.is_visible:
+ section_key = cfg.page_key or default_page_map.get(field_name, '')
+ section_hidden = (
+ form_type in {'onboarding', 'offboarding'}
+ and section_key not in locked_sections
+ and section_key in section_configs
+ and not section_configs[section_key].is_visible
+ )
+ if field_name not in locked and (not cfg.is_visible or section_hidden):
form.fields.pop(field_name, None)
ordered_items = sorted(
@@ -184,9 +258,138 @@ def apply_form_field_config(form_type: str, form) -> None:
),
)
form.fields = OrderedDict(ordered_items)
- if form_type == 'onboarding':
+ if form_type in {'onboarding', 'offboarding'}:
form._field_page_keys = {
- name: (configs[name].page_key or ONBOARDING_DEFAULT_PAGE.get(name, 'abschluss'))
+ name: (configs[name].page_key or default_page_map.get(name, ''))
for name in form.fields.keys()
if name in configs
}
+
+
+FORM_PRESETS = {
+ 'onboarding': {
+ 'standard': {
+ 'label': 'Standard',
+ 'sections': {
+ 'stammdaten': True,
+ 'vertrag': True,
+ 'itsetup': True,
+ 'abschluss': True,
+ },
+ 'fields': {},
+ },
+ 'lean': {
+ 'label': 'Lean',
+ 'sections': {
+ 'stammdaten': True,
+ 'vertrag': True,
+ 'itsetup': False,
+ 'abschluss': True,
+ },
+ 'fields': {
+ 'gender': {'is_visible': False},
+ 'order_business_cards': {'is_visible': False},
+ 'business_card_name': {'is_visible': False},
+ 'business_card_title': {'is_visible': False},
+ 'business_card_email': {'is_visible': False},
+ 'business_card_phone': {'is_visible': False},
+ 'employment_end_date': {'is_visible': False},
+ 'group_mailboxes_required_choice': {'is_visible': False},
+ 'group_mailboxes': {'is_visible': False},
+ 'additional_notes': {'is_required': False},
+ },
+ },
+ 'it_heavy': {
+ 'label': 'IT-heavy',
+ 'sections': {
+ 'stammdaten': True,
+ 'vertrag': True,
+ 'itsetup': True,
+ 'abschluss': True,
+ },
+ 'fields': {
+ 'needed_devices_multi': {'is_required': True},
+ 'needed_software_multi': {'is_required': True},
+ 'needed_accesses_multi': {'is_required': True},
+ 'needed_workspace_groups_multi': {'is_required': True},
+ 'needed_resources_multi': {'is_required': True},
+ 'additional_hardware_needed_choice': {'is_visible': True},
+ 'additional_software_needed_choice': {'is_visible': True},
+ 'additional_access_needed_choice': {'is_visible': True},
+ 'successor_required_choice': {'is_visible': True},
+ },
+ },
+ },
+ 'offboarding': {
+ 'standard': {
+ 'label': 'Standard',
+ 'sections': {
+ 'mitarbeitende': True,
+ 'austritt': True,
+ 'abschluss': True,
+ },
+ 'fields': {},
+ },
+ 'lean': {
+ 'label': 'Lean',
+ 'sections': {
+ 'mitarbeitende': True,
+ 'austritt': True,
+ 'abschluss': False,
+ },
+ 'fields': {
+ 'department': {'is_visible': False},
+ 'job_title': {'is_visible': False},
+ 'notes': {'is_visible': False},
+ },
+ },
+ 'hr_heavy': {
+ 'label': 'HR-heavy',
+ 'sections': {
+ 'mitarbeitende': True,
+ 'austritt': True,
+ 'abschluss': True,
+ },
+ 'fields': {
+ 'department': {'is_visible': True, 'is_required': True},
+ 'job_title': {'is_visible': True, 'is_required': True},
+ 'notes': {'is_visible': True, 'is_required': True},
+ },
+ },
+ },
+}
+
+
+def apply_form_preset(form_type: str, preset_key: str) -> bool:
+ preset = FORM_PRESETS.get(form_type, {}).get(preset_key)
+ if not preset:
+ return False
+
+ locked_fields = LOCKED_FIELD_RULES.get(form_type, set())
+ locked_sections = LOCKED_SECTION_RULES.get(form_type, set())
+ default_names = list(DEFAULT_FIELD_ORDER.get(form_type, []))
+ ensure_form_field_configs(form_type, default_names)
+ section_configs = ensure_form_section_configs(form_type)
+
+ for section_key, is_visible in preset.get('sections', {}).items():
+ cfg = section_configs.get(section_key)
+ if not cfg or section_key in locked_sections:
+ continue
+ cfg.is_visible = bool(is_visible)
+ cfg.save(update_fields=['is_visible'])
+
+ for cfg in FormFieldConfig.objects.filter(form_type=form_type):
+ if cfg.field_name in locked_fields:
+ cfg.is_visible = True
+ cfg.is_required = None
+ else:
+ cfg.is_visible = True
+ cfg.is_required = None
+ override = preset.get('fields', {}).get(cfg.field_name, {})
+ if 'is_visible' in override:
+ cfg.is_visible = bool(override['is_visible'])
+ if 'is_required' in override:
+ cfg.is_required = override['is_required']
+ cfg.save(update_fields=['is_visible', 'is_required'])
+
+ return True
diff --git a/backend/workflows/migrations/0053_formsectionconfig.py b/backend/workflows/migrations/0053_formsectionconfig.py
new file mode 100644
index 0000000..0a4c6ce
--- /dev/null
+++ b/backend/workflows/migrations/0053_formsectionconfig.py
@@ -0,0 +1,37 @@
+from django.db import migrations, models
+
+
+def seed_onboarding_sections(apps, schema_editor):
+ FormSectionConfig = apps.get_model('workflows', 'FormSectionConfig')
+ for section_key in ['stammdaten', 'vertrag', 'itsetup', 'abschluss']:
+ FormSectionConfig.objects.get_or_create(
+ form_type='onboarding',
+ section_key=section_key,
+ defaults={'is_visible': True},
+ )
+
+
+class Migration(migrations.Migration):
+
+ dependencies = [
+ ('workflows', '0052_userprofile_notification_preferences'),
+ ]
+
+ operations = [
+ migrations.CreateModel(
+ name='FormSectionConfig',
+ fields=[
+ ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
+ ('form_type', models.CharField(choices=[('onboarding', 'Onboarding')], max_length=20)),
+ ('section_key', models.CharField(choices=[('stammdaten', 'Stammdaten'), ('vertrag', 'Vertrag'), ('itsetup', 'IT-Setup'), ('abschluss', 'Abschluss')], max_length=20)),
+ ('is_visible', models.BooleanField(default=True)),
+ ],
+ options={
+ 'verbose_name': 'Formularabschnitt-Konfiguration',
+ 'verbose_name_plural': 'Formularabschnitt-Konfigurationen',
+ 'ordering': ['form_type', 'section_key'],
+ 'unique_together': {('form_type', 'section_key')},
+ },
+ ),
+ migrations.RunPython(seed_onboarding_sections, migrations.RunPython.noop),
+ ]
diff --git a/backend/workflows/models.py b/backend/workflows/models.py
index 963315f..96c18a9 100644
--- a/backend/workflows/models.py
+++ b/backend/workflows/models.py
@@ -516,6 +516,31 @@ class FormFieldConfig(models.Model):
return self.help_text_override.strip()
+class FormSectionConfig(models.Model):
+ FORM_CHOICES = [
+ ('onboarding', _('Onboarding')),
+ ]
+ SECTION_CHOICES = [
+ ('stammdaten', _('Stammdaten')),
+ ('vertrag', _('Vertrag')),
+ ('itsetup', _('IT-Setup')),
+ ('abschluss', _('Abschluss')),
+ ]
+
+ form_type = models.CharField(max_length=20, choices=FORM_CHOICES)
+ section_key = models.CharField(max_length=20, choices=SECTION_CHOICES)
+ is_visible = models.BooleanField(default=True)
+
+ class Meta:
+ ordering = ['form_type', 'section_key']
+ unique_together = ('form_type', 'section_key')
+ verbose_name = 'Formularabschnitt-Konfiguration'
+ verbose_name_plural = 'Formularabschnitt-Konfigurationen'
+
+ def __str__(self) -> str:
+ return f'{self.form_type}: {self.section_key}'
+
+
class NotificationTemplate(models.Model):
TEMPLATE_CHOICES = [
('onboarding_it', _('Onboarding: IT')),
diff --git a/backend/workflows/static/workflows/css/form_builder.css b/backend/workflows/static/workflows/css/form_builder.css
index 8de88a6..fce3a2e 100644
--- a/backend/workflows/static/workflows/css/form_builder.css
+++ b/backend/workflows/static/workflows/css/form_builder.css
@@ -1,72 +1,98 @@
body {
margin: 0;
- font-family: Arial, sans-serif;
- background: #f4f7fb;
- color: #1f2937;
+ font-family: "IBM Plex Sans", "Segoe UI", sans-serif;
+ background:
+ radial-gradient(circle at top right, rgba(0, 120, 255, 0.08), transparent 28%),
+ linear-gradient(180deg, #eef4fb 0%, #f7f9fc 100%);
+ color: #142033;
}
.shell {
- width: min(1280px, 94%);
- margin: 20px auto 28px;
- background: #ffffff;
- border: 1px solid #d8e2f0;
- border-radius: 14px;
- padding: 18px;
- box-shadow: 0 10px 24px rgba(15, 23, 42, 0.08);
+ width: min(1320px, 94%);
+ margin: 20px auto 32px;
+ background: rgba(255, 255, 255, 0.92);
+ border: 1px solid rgba(191, 204, 222, 0.8);
+ border-radius: 20px;
+ padding: 20px;
+ box-shadow: 0 22px 60px rgba(15, 23, 42, 0.08);
+ backdrop-filter: blur(12px);
}
-.topbar {
+.builder-hero,
+.builder-panel,
+.builder-stat-card,
+.section-rule-card,
+.field-card,
+.options-panel {
+ animation: builderFadeIn 0.32s ease;
+}
+
+.builder-hero {
display: flex;
- align-items: center;
+ align-items: flex-end;
justify-content: space-between;
- gap: 12px;
- margin-bottom: 10px;
+ gap: 20px;
+ padding: 8px 0 6px;
}
-.brand-logo {
- width: 190px;
- max-width: 100%;
- height: auto;
- display: block;
+.builder-hero-copy {
+ max-width: 760px;
}
-.header h1 {
- margin: 0;
- font-size: 28px;
-}
-
-.header p {
- margin: 6px 0 0;
- color: #64748b;
-}
-
-.toolbar {
- margin-top: 14px;
- display: flex;
+.builder-eyebrow {
+ display: inline-flex;
align-items: center;
gap: 8px;
+ margin-bottom: 10px;
+ padding: 6px 11px;
+ border-radius: 999px;
+ background: #e9f2ff;
+ color: #174ea6;
+ font-size: 12px;
+ font-weight: 700;
+ letter-spacing: 0.04em;
+ text-transform: uppercase;
+}
+
+.builder-hero h1 {
+ margin: 0;
+ font-size: clamp(30px, 4vw, 40px);
+ line-height: 1.02;
+}
+
+.builder-hero-actions {
+ display: flex;
+ align-items: center;
+ gap: 10px;
flex-wrap: wrap;
+ justify-content: flex-end;
}
.tab {
- border: 1px solid #cbd5e1;
+ border: 1px solid #c6d1e1;
border-radius: 999px;
- padding: 8px 14px;
+ padding: 9px 15px;
text-decoration: none;
- color: #1f2937;
- background: #f8fafc;
- font-weight: 600;
+ color: #1c2a41;
+ background: #f8fbff;
+ font-weight: 700;
+ transition: transform 0.18s ease, border-color 0.18s ease, background 0.18s ease;
+}
+
+.tab:hover {
+ transform: translateY(-1px);
+ border-color: #9db4d2;
}
.tab.active {
- background: #000078;
+ background: linear-gradient(135deg, #0f3b7a 0%, #1759b8 100%);
color: #ffffff;
- border-color: #000078;
+ border-color: #1759b8;
}
.status {
min-height: 22px;
- margin: 10px 0 8px;
+ margin: 14px 0 10px;
color: #334155;
font-size: 14px;
}
@@ -83,11 +109,401 @@ body {
color: #166534;
}
+.builder-overview {
+ margin-top: 12px;
+ display: grid;
+ grid-template-columns: repeat(4, minmax(0, 1fr));
+ gap: 12px;
+}
+
+.builder-stat-card,
+.builder-panel,
+.options-panel {
+ border: 1px solid rgba(201, 212, 226, 0.95);
+ border-radius: 18px;
+ background: linear-gradient(180deg, rgba(255, 255, 255, 0.98), rgba(247, 250, 255, 0.98));
+ box-shadow: 0 10px 24px rgba(15, 23, 42, 0.05);
+}
+
+.builder-stat-card {
+ padding: 14px 16px;
+ transition: transform 0.2s ease, box-shadow 0.2s ease, border-color 0.2s ease;
+}
+
+.builder-stat-card:hover {
+ transform: translateY(-2px);
+ border-color: rgba(146, 170, 199, 0.95);
+ box-shadow: 0 16px 28px rgba(15, 23, 42, 0.08);
+}
+
+.builder-stat-label {
+ display: block;
+ color: #65758f;
+ font-size: 12px;
+ font-weight: 700;
+ letter-spacing: 0.03em;
+ text-transform: uppercase;
+}
+
+.builder-stat-card strong {
+ display: block;
+ margin-top: 6px;
+ font-size: 28px;
+ line-height: 1;
+ color: #101c30;
+}
+
+.builder-panel-head h2,
+.options-head h2 {
+ margin: 0;
+ color: #142033;
+}
+
+.mini {
+ color: #61718a;
+ font-size: 13px;
+ line-height: 1.55;
+}
+
+.builder-quicknav {
+ margin-top: 12px;
+ display: flex;
+ align-items: center;
+ gap: 8px;
+ flex-wrap: wrap;
+}
+
+.builder-quicknav a {
+ display: inline-flex;
+ align-items: center;
+ min-height: 34px;
+ padding: 0 12px;
+ border: 1px solid #d1dbea;
+ border-radius: 999px;
+ background: #f7fbff;
+ color: #304159;
+ font-size: 13px;
+ font-weight: 700;
+ text-decoration: none;
+ transition: transform 0.18s ease, border-color 0.18s ease, background-color 0.18s ease, box-shadow 0.18s ease;
+}
+
+.builder-quicknav a:hover {
+ transform: translateY(-1px);
+ border-color: #adc2dd;
+ background: #ffffff;
+ box-shadow: 0 10px 18px rgba(15, 23, 42, 0.06);
+}
+
+.builder-preset-bar {
+ margin-top: 12px;
+ display: flex;
+ justify-content: flex-end;
+}
+
+.builder-preset-form {
+ display: flex;
+ align-items: center;
+ flex-wrap: wrap;
+ gap: 8px;
+}
+
+.builder-preset-label {
+ color: #61718a;
+ font-size: 12px;
+ font-weight: 800;
+ letter-spacing: 0.04em;
+ text-transform: uppercase;
+}
+
+.builder-preset-form select {
+ min-height: 36px;
+ padding: 0 12px;
+ border: 1px solid #cfdbeb;
+ border-radius: 999px;
+ background: linear-gradient(180deg, #ffffff, #f6faff);
+ color: #24405f;
+ font-size: 13px;
+ font-weight: 700;
+}
+
+.builder-panel {
+ margin-top: 14px;
+ padding: 16px;
+}
+
+.builder-panel-head,
+.options-head {
+ display: flex;
+ align-items: flex-start;
+ justify-content: space-between;
+ gap: 14px;
+ margin-bottom: 12px;
+}
+
+.options-head-inline {
+ margin-bottom: 14px;
+}
+
+.builder-accordion {
+ padding: 0;
+ overflow: hidden;
+}
+
+.nested-accordion {
+ padding: 0;
+ overflow: hidden;
+}
+
+.nested-accordion-summary {
+ list-style: none;
+ cursor: pointer;
+ padding: 14px 16px;
+ transition: background-color 0.18s ease;
+}
+
+.nested-accordion-summary::-webkit-details-marker {
+ display: none;
+}
+
+.nested-accordion-summary .options-head {
+ margin-bottom: 0;
+}
+
+.nested-accordion-summary:hover {
+ background: rgba(242, 247, 255, 0.72);
+}
+
+.nested-accordion[open] .nested-accordion-summary {
+ border-bottom: 1px solid rgba(201, 212, 226, 0.8);
+}
+
+.nested-accordion:not([open]) .builder-panel-toggle::after {
+ transform: rotate(-90deg);
+}
+
+.nested-accordion[open] .builder-panel-toggle {
+ color: #194ea7;
+}
+
+.nested-accordion-body {
+ padding: 14px 16px 16px;
+}
+
+.nested-accordion[open] .nested-accordion-body {
+ animation: builderReveal 0.24s ease;
+}
+
+.builder-panel-summary {
+ list-style: none;
+ cursor: pointer;
+ padding: 14px 16px;
+ transition: background-color 0.18s ease;
+}
+
+.builder-panel-summary::-webkit-details-marker {
+ display: none;
+}
+
+.builder-panel-summary .builder-panel-head {
+ margin-bottom: 0;
+}
+
+.builder-panel-summary:hover {
+ background: rgba(242, 247, 255, 0.72);
+}
+
+.builder-panel-toggle {
+ display: inline-flex;
+ align-items: center;
+ gap: 8px;
+ color: #5f7089;
+ font-size: 12px;
+ font-weight: 700;
+ text-transform: uppercase;
+ letter-spacing: 0.04em;
+}
+
+.builder-panel-toggle::after {
+ content: "▾";
+ font-size: 13px;
+ line-height: 1;
+ transition: transform 0.18s ease;
+}
+
+.builder-accordion:not([open]) .builder-panel-toggle::after {
+ transform: rotate(-90deg);
+}
+
+.builder-accordion[open] .builder-panel-toggle {
+ color: #194ea7;
+}
+
+.builder-accordion[open] .builder-panel-toggle::before {
+ content: "";
+}
+
+.builder-accordion[open] .builder-panel-summary {
+ border-bottom: 1px solid rgba(201, 212, 226, 0.8);
+}
+
+.builder-panel-body {
+ padding: 14px 16px 16px;
+}
+
+.builder-accordion[open] .builder-panel-body {
+ animation: builderReveal 0.24s ease;
+}
+
+.builder-rule-layout {
+ display: grid;
+ grid-template-columns: minmax(300px, 0.85fr) minmax(0, 1.15fr);
+ gap: 14px;
+}
+
+.builder-stack-layout {
+ display: grid;
+ gap: 14px;
+}
+
+.preview-shell {
+ display: grid;
+ gap: 12px;
+}
+
+.preview-section {
+ border: 1px solid #d7e0ec;
+ border-radius: 14px;
+ background: linear-gradient(180deg, #f8fbff 0%, #ffffff 100%);
+ overflow: hidden;
+}
+
+.preview-section-head {
+ display: flex;
+ align-items: center;
+ justify-content: space-between;
+ gap: 10px;
+ padding: 12px 14px;
+ border-bottom: 1px solid #dfe7f1;
+ background: #f2f7ff;
+}
+
+.preview-section-head h3 {
+ margin: 0;
+ font-size: 15px;
+ color: #142033;
+}
+
+.preview-chip-list {
+ display: flex;
+ flex-wrap: wrap;
+ gap: 8px;
+ padding: 14px;
+}
+
+.preview-chip {
+ display: inline-flex;
+ align-items: center;
+ min-height: 32px;
+ padding: 0 10px;
+ border: 1px solid #d8e1ec;
+ border-radius: 999px;
+ background: #ffffff;
+ color: #304159;
+ font-size: 13px;
+ font-weight: 700;
+}
+
+.preview-chip.is-locked {
+ background: #eef2ff;
+ border-color: #c7d2fe;
+ color: #3730a3;
+}
+
+.field-rule-groups {
+ display: grid;
+ gap: 12px;
+}
+
+.field-rule-group {
+ border: 1px solid #d7e0ec;
+ border-radius: 14px;
+ background: linear-gradient(180deg, #f8fbff 0%, #ffffff 100%);
+ overflow: hidden;
+ transition: transform 0.2s ease, box-shadow 0.2s ease, border-color 0.2s ease;
+}
+
+.field-rule-group:hover {
+ transform: translateY(-1px);
+ border-color: #bfd0e4;
+ box-shadow: 0 14px 26px rgba(15, 23, 42, 0.06);
+}
+
+.field-rule-group-head {
+ display: flex;
+ align-items: center;
+ justify-content: space-between;
+ gap: 10px;
+ padding: 12px 14px;
+ border-bottom: 1px solid #dfe7f1;
+ background: #f2f7ff;
+}
+
+.field-rule-group-head h3 {
+ margin: 0;
+ font-size: 15px;
+ color: #142033;
+}
+
+.field-rule-list {
+ display: grid;
+}
+
+.field-rule-row {
+ display: grid;
+ grid-template-columns: minmax(220px, 1.4fr) 120px 160px 120px;
+ gap: 12px;
+ align-items: center;
+ padding: 12px 14px;
+ border-top: 1px solid #edf2f7;
+ transition: background-color 0.18s ease;
+}
+
+.field-rule-row:first-child {
+ border-top: 0;
+}
+
+.field-rule-row:hover {
+ background: rgba(246, 250, 255, 0.92);
+}
+
+.field-rule-main strong {
+ display: block;
+ color: #162133;
+}
+
+.field-rule-control {
+ display: grid;
+ gap: 6px;
+ color: #5f7089;
+ font-size: 12px;
+ font-weight: 700;
+}
+
+.field-rule-control input[type='checkbox'] {
+ width: 16px;
+ height: 16px;
+}
+
+.field-rule-status {
+ display: flex;
+ justify-content: flex-end;
+}
+
.columns {
- margin-top: 8px;
display: grid;
grid-template-columns: repeat(4, minmax(220px, 1fr));
- gap: 10px;
+ gap: 12px;
}
.columns.single {
@@ -95,28 +511,47 @@ body {
}
.column {
- border: 1px solid #d4dce7;
- border-radius: 12px;
- background: #f9fbff;
+ border: 1px solid #d7e0ec;
+ border-radius: 16px;
+ background: linear-gradient(180deg, #f7faff 0%, #fdfefe 100%);
display: flex;
flex-direction: column;
min-height: 460px;
+ overflow: hidden;
+ transition: transform 0.2s ease, box-shadow 0.2s ease, border-color 0.2s ease;
}
-.column h2 {
+.column:hover {
+ transform: translateY(-2px);
+ border-color: #bfd0e4;
+ box-shadow: 0 16px 28px rgba(15, 23, 42, 0.07);
+}
+
+.column-head {
+ display: flex;
+ align-items: center;
+ justify-content: space-between;
+ gap: 10px;
+ padding: 13px 14px;
+ border-bottom: 1px solid #deE7f1;
+ background: linear-gradient(180deg, #eef5ff, #f7fbff);
+}
+
+.column-head h3 {
margin: 0;
- padding: 10px 12px;
- border-bottom: 1px solid #dbe3ee;
font-size: 16px;
- color: #0f172a;
- background: #edf3fb;
- border-radius: 12px 12px 0 0;
+}
+
+.column-count {
+ color: #5c6d87;
+ font-size: 12px;
+ font-weight: 700;
}
.dropzone {
- padding: 10px;
+ padding: 12px;
display: grid;
- gap: 8px;
+ gap: 10px;
align-content: start;
min-height: 140px;
flex: 1;
@@ -127,14 +562,22 @@ body {
}
.field-card {
- background: #ffffff;
- border: 1px solid #d3dbe8;
- border-radius: 10px;
- padding: 9px 10px;
+ background: rgba(255, 255, 255, 0.96);
+ border: 1px solid #d7dfeb;
+ border-radius: 14px;
+ padding: 11px 12px;
display: flex;
justify-content: space-between;
- gap: 8px;
+ align-items: flex-start;
+ gap: 10px;
cursor: move;
+ transition: transform 0.18s ease, box-shadow 0.18s ease, border-color 0.18s ease;
+}
+
+.field-card:hover {
+ transform: translateY(-1px);
+ border-color: #b9cadf;
+ box-shadow: 0 12px 20px rgba(15, 23, 42, 0.06);
}
.field-card.dragging {
@@ -145,13 +588,20 @@ body {
font-weight: 700;
font-size: 14px;
color: #0f172a;
+ overflow-wrap: anywhere;
}
.field-name {
font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
font-size: 12px;
color: #64748b;
- margin-top: 2px;
+ margin-top: 3px;
+ overflow-wrap: anywhere;
+}
+
+.field-main {
+ min-width: 0;
+ flex: 1 1 auto;
}
.badges {
@@ -159,13 +609,15 @@ body {
gap: 6px;
align-items: center;
flex-wrap: wrap;
+ justify-content: flex-end;
+ flex: 0 0 auto;
}
.badge {
font-size: 11px;
border-radius: 999px;
border: 1px solid #d1d5db;
- padding: 2px 7px;
+ padding: 3px 8px;
background: #f8fafc;
color: #334155;
}
@@ -189,24 +641,7 @@ body {
}
.options-panel {
- margin-top: 16px;
- border: 1px solid #d4dce7;
- border-radius: 12px;
- background: #ffffff;
- padding: 12px;
-}
-
-.options-head {
- display: flex;
- align-items: center;
- justify-content: space-between;
- gap: 10px;
- margin-bottom: 10px;
-}
-
-.options-head h2 {
- margin: 0;
- font-size: 18px;
+ padding: 14px;
}
.category-switch {
@@ -215,23 +650,22 @@ body {
gap: 8px;
}
-.category-switch select {
+.category-switch select,
+.option-table select,
+.add-option-form input,
+.option-table input[type='text'] {
border: 1px solid #cbd5e1;
- border-radius: 8px;
- padding: 6px 8px;
+ border-radius: 10px;
+ padding: 8px 10px;
+ box-sizing: border-box;
+ background: #fff;
}
.add-option-form {
display: grid;
grid-template-columns: minmax(180px, 1fr) minmax(180px, 1fr) minmax(180px, 1fr) auto;
gap: 8px;
- margin-bottom: 10px;
-}
-
-.add-option-form input {
- border: 1px solid #cbd5e1;
- border-radius: 8px;
- padding: 8px 9px;
+ margin-bottom: 12px;
}
.option-table-wrap {
@@ -246,21 +680,22 @@ body {
.option-table th,
.option-table td {
border: 1px solid #e2e8f0;
- padding: 7px 8px;
+ padding: 8px 9px;
text-align: left;
vertical-align: top;
}
.option-table th {
- background: #f8fafc;
+ background: #f8fbff;
+ color: #3d4c63;
}
-.option-table input[type='text'] {
- width: 100%;
- border: 1px solid #cbd5e1;
- border-radius: 7px;
- padding: 6px 8px;
- box-sizing: border-box;
+.option-table-group-row th {
+ background: #eef5ff;
+ color: #17335e;
+ font-size: 12px;
+ text-transform: uppercase;
+ letter-spacing: 0.04em;
}
.option-row {
@@ -279,7 +714,7 @@ body {
width: 28px;
height: 28px;
border: 1px solid #cbd5e1;
- border-radius: 6px;
+ border-radius: 8px;
background: #f8fafc;
color: #475569;
font-size: 14px;
@@ -288,28 +723,146 @@ body {
}
.options-actions {
- margin-top: 10px;
+ margin-top: 12px;
display: flex;
justify-content: flex-end;
}
-@media (max-width: 1120px) {
+.section-rule-grid {
+ display: grid;
+ grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
+ gap: 10px;
+}
+
+.section-rule-card {
+ display: flex;
+ align-items: center;
+ justify-content: space-between;
+ gap: 12px;
+ padding: 13px 14px;
+ border: 1px solid #d6e0ec;
+ border-radius: 14px;
+ background: linear-gradient(180deg, #f9fbff, #ffffff);
+}
+
+.section-rule-card.is-locked {
+ background: linear-gradient(180deg, #f4f7fb, #fafcff);
+}
+
+.section-rule-copy {
+ display: grid;
+ gap: 4px;
+}
+
+.section-rule-copy strong {
+ color: #0f172a;
+ font-size: 14px;
+}
+
+.section-rule-copy span,
+.mini {
+ color: #64748b;
+ font-size: 12px;
+ line-height: 1.45;
+}
+
+.section-rule-toggle {
+ display: inline-flex;
+ align-items: center;
+ gap: 8px;
+}
+
+@keyframes builderFadeIn {
+ from {
+ opacity: 0;
+ transform: translateY(10px);
+ }
+ to {
+ opacity: 1;
+ transform: translateY(0);
+ }
+}
+
+@keyframes builderReveal {
+ from {
+ opacity: 0;
+ transform: translateY(-4px);
+ }
+ to {
+ opacity: 1;
+ transform: translateY(0);
+ }
+}
+
+@media (prefers-reduced-motion: reduce) {
+ .builder-hero,
+ .builder-panel,
+ .builder-stat-card,
+ .section-rule-card,
+ .field-card,
+ .options-panel {
+ animation: none;
+ }
+
+ .field-card,
+ .tab,
+ .builder-stat-card,
+ .builder-quicknav a,
+ .builder-panel-summary,
+ .field-rule-group,
+ .field-rule-row,
+ .column {
+ transition: none;
+ }
+
+ .builder-accordion[open] .builder-panel-body {
+ animation: none;
+ }
+}
+
+@media (max-width: 1220px) {
+ .builder-overview {
+ grid-template-columns: repeat(2, minmax(0, 1fr));
+ }
+
+ .builder-rule-layout,
.columns {
grid-template-columns: repeat(2, minmax(220px, 1fr));
}
}
+@media (max-width: 900px) {
+ .builder-hero,
+ .builder-panel-head,
+ .options-head {
+ flex-direction: column;
+ align-items: flex-start;
+ }
+
+ .builder-hero-actions {
+ justify-content: flex-start;
+ }
+
+ .builder-rule-layout {
+ grid-template-columns: 1fr;
+ }
+}
+
@media (max-width: 760px) {
+ .builder-overview,
.columns {
grid-template-columns: 1fr;
}
+ .field-rule-row {
+ grid-template-columns: 1fr;
+ }
+
+ .field-rule-status {
+ justify-content: flex-start;
+ }
+
.add-option-form {
grid-template-columns: 1fr;
}
-
- .options-head {
- flex-direction: column;
- align-items: flex-start;
- }
}
diff --git a/backend/workflows/static/workflows/css/offboarding_form.css b/backend/workflows/static/workflows/css/offboarding_form.css
index 34a1a12..3c2a507 100644
--- a/backend/workflows/static/workflows/css/offboarding_form.css
+++ b/backend/workflows/static/workflows/css/offboarding_form.css
@@ -14,6 +14,7 @@ body {
.card { background: linear-gradient(180deg, #ffffff, #fbfcff); border: 1px solid #d9dcf3; border-radius: 14px; padding: 18px; margin-bottom: 14px; box-shadow: 0 10px 24px rgba(0, 0, 120, 0.08); }
.wrap-body .card:last-child { margin-bottom: 0; }
h1 { margin-top: 0; color: #000078; }
+h2 { margin: 0; color: #17335e; font-size: 18px; }
.grid { display: grid; grid-template-columns: 1fr 1fr; gap: 12px; }
.field { margin-bottom: 12px; }
.field-full { grid-column: 1 / -1; }
@@ -21,6 +22,11 @@ label { display: block; font-weight: 600; margin-bottom: 6px; }
input, textarea { width: 100%; min-height: 44px; padding: 9px 11px; box-sizing: border-box; border: 1px solid #d4dbf7; border-radius: 10px; background: #fff; }
textarea { min-height: 120px; resize: vertical; }
.hint { color: #64748b; font-size: 12px; margin-top: 4px; }
+.offboarding-sections { display: grid; gap: 14px; margin-bottom: 14px; }
+.offboarding-section-card { border: 1px solid #dbe5f1; border-radius: 14px; background: linear-gradient(180deg, #f9fbff, #ffffff); overflow: hidden; box-shadow: 0 8px 20px rgba(15, 23, 42, 0.05); }
+.offboarding-section-head { padding: 14px 16px; border-bottom: 1px solid #e2e8f4; background: #f2f7ff; }
+.offboarding-section-head p { margin: 4px 0 0; color: #5f7089; font-size: 13px; }
+.offboarding-section-card .grid { padding: 16px; }
.results a { display: inline-block; margin: 4px 8px 4px 0; padding: 6px 8px; border: 1px solid #d4dbf7; border-radius: 6px; text-decoration: none; color: #000078; background: #f7f8ff; }
.errorlist { color: #b91c1c; margin: 4px 0; }
.popup-backdrop { position: fixed; inset: 0; background: rgba(15, 23, 42, 0.38); display: none; align-items: center; justify-content: center; z-index: 1000; }
diff --git a/backend/workflows/templates/workflows/form_builder.html b/backend/workflows/templates/workflows/form_builder.html
index 58697b3..2e1cef1 100644
--- a/backend/workflows/templates/workflows/form_builder.html
+++ b/backend/workflows/templates/workflows/form_builder.html
@@ -10,153 +10,399 @@
{% block shell_body %}
{% include 'workflows/includes/app_header.html' with header_show_home=1 header_inside_shell=1 %}
-
+
+
+ {% trans "Deployment Configuration" %}
+
{% trans "Form Builder" %}
+
+
+ {% for key, label in form_types %}
+
+ {{ label }}
+
+ {% endfor %}
+
{% trans "Reihenfolge speichern" %}
+
+
{% include 'workflows/includes/messages.html' %}
-
-
-