snapshot: preserve extended branding layer and branding UI polish
This commit is contained in:
@@ -2,14 +2,14 @@ msgid ""
|
|||||||
msgstr ""
|
msgstr ""
|
||||||
"Project-Id-Version: tubco-portal\n"
|
"Project-Id-Version: tubco-portal\n"
|
||||||
"Report-Msgid-Bugs-To: \n"
|
"Report-Msgid-Bugs-To: \n"
|
||||||
"POT-Creation-Date: 2026-03-26 10:55+0000\n"
|
"POT-Creation-Date: 2026-03-26 11:02+0000\n"
|
||||||
"PO-Revision-Date: 2026-03-24 00:00+0000\n"
|
"PO-Revision-Date: 2026-03-24 00:00+0000\n"
|
||||||
"Language: en\n"
|
"Language: en\n"
|
||||||
"MIME-Version: 1.0\n"
|
"MIME-Version: 1.0\n"
|
||||||
"Content-Type: text/plain; charset=UTF-8\n"
|
"Content-Type: text/plain; charset=UTF-8\n"
|
||||||
"Content-Transfer-Encoding: 8bit\n"
|
"Content-Transfer-Encoding: 8bit\n"
|
||||||
|
|
||||||
#: workflows/app_registry.py:32 workflows/models.py:261 workflows/models.py:342
|
#: workflows/app_registry.py:32 workflows/models.py:273 workflows/models.py:354
|
||||||
#: workflows/templates/workflows/onboarding_form.html:25
|
#: workflows/templates/workflows/onboarding_form.html:25
|
||||||
#: workflows/templates/workflows/requests_dashboard.html:68
|
#: workflows/templates/workflows/requests_dashboard.html:68
|
||||||
#: workflows/templates/workflows/requests_dashboard.html:131
|
#: workflows/templates/workflows/requests_dashboard.html:131
|
||||||
@@ -36,7 +36,7 @@ msgstr "Multi-step form"
|
|||||||
msgid "E-Mail Routing"
|
msgid "E-Mail Routing"
|
||||||
msgstr "Email routing"
|
msgstr "Email routing"
|
||||||
|
|
||||||
#: workflows/app_registry.py:43 workflows/models.py:262 workflows/models.py:343
|
#: workflows/app_registry.py:43 workflows/models.py:274 workflows/models.py:355
|
||||||
#: workflows/templates/workflows/requests_dashboard.html:78
|
#: workflows/templates/workflows/requests_dashboard.html:78
|
||||||
#: workflows/templates/workflows/requests_dashboard.html:132
|
#: workflows/templates/workflows/requests_dashboard.html:132
|
||||||
msgid "Offboarding"
|
msgid "Offboarding"
|
||||||
@@ -213,7 +213,7 @@ msgstr "Django Admin"
|
|||||||
msgid "Vollständige Datenverwaltung."
|
msgid "Vollständige Datenverwaltung."
|
||||||
msgstr "Full data management."
|
msgstr "Full data management."
|
||||||
|
|
||||||
#: workflows/app_registry.py:165 workflows/models.py:68
|
#: workflows/app_registry.py:165 workflows/models.py:80
|
||||||
msgid "Apps"
|
msgid "Apps"
|
||||||
msgstr "Apps"
|
msgstr "Apps"
|
||||||
|
|
||||||
@@ -221,7 +221,7 @@ msgstr "Apps"
|
|||||||
msgid "Wählen Sie den gewünschten Prozess."
|
msgid "Wählen Sie den gewünschten Prozess."
|
||||||
msgstr "Choose the desired process."
|
msgstr "Choose the desired process."
|
||||||
|
|
||||||
#: workflows/app_registry.py:171 workflows/models.py:69
|
#: workflows/app_registry.py:171 workflows/models.py:81
|
||||||
msgid "Platform Apps"
|
msgid "Platform Apps"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
@@ -231,7 +231,7 @@ msgstr ""
|
|||||||
msgid "Produktweite Konfiguration und Produktsteuerung."
|
msgid "Produktweite Konfiguration und Produktsteuerung."
|
||||||
msgstr "Configuration, tests, and controls."
|
msgstr "Configuration, tests, and controls."
|
||||||
|
|
||||||
#: workflows/app_registry.py:177 workflows/models.py:70
|
#: workflows/app_registry.py:177 workflows/models.py:82
|
||||||
msgid "Admin Apps"
|
msgid "Admin Apps"
|
||||||
msgstr "Admin Apps"
|
msgstr "Admin Apps"
|
||||||
|
|
||||||
@@ -338,307 +338,339 @@ msgstr "Invalid role."
|
|||||||
msgid "Nur Platform Owner dürfen diese Rolle vergeben."
|
msgid "Nur Platform Owner dürfen diese Rolle vergeben."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: workflows/forms.py:188
|
#: workflows/forms.py:195
|
||||||
msgid "Portal-Titel"
|
msgid "Portal-Titel"
|
||||||
msgstr "Portal title"
|
msgstr "Portal title"
|
||||||
|
|
||||||
#: workflows/forms.py:189
|
#: workflows/forms.py:196
|
||||||
msgid "Firmenname"
|
msgid "Firmenname"
|
||||||
msgstr "Company name"
|
msgstr "Company name"
|
||||||
|
|
||||||
#: workflows/forms.py:190
|
#: workflows/forms.py:197
|
||||||
#, fuzzy
|
#, fuzzy
|
||||||
#| msgid "Firmenname"
|
#| msgid "Firmenname"
|
||||||
msgid "Firmen-Domain"
|
msgid "Firmen-Domain"
|
||||||
msgstr "Company name"
|
msgstr "Company name"
|
||||||
|
|
||||||
#: workflows/forms.py:191
|
#: workflows/forms.py:198
|
||||||
msgid "Support-E-Mail"
|
msgid "Support-E-Mail"
|
||||||
msgstr "Support email"
|
msgstr "Support email"
|
||||||
|
|
||||||
#: workflows/forms.py:192
|
#: workflows/forms.py:199
|
||||||
|
msgid "Absender-Anzeigename"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: workflows/forms.py:200
|
||||||
|
msgid "Login-Untertitel"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: workflows/forms.py:201
|
||||||
|
msgid "Footer-Text DE"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: workflows/forms.py:202
|
||||||
|
msgid "Footer-Text EN"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: workflows/forms.py:203
|
||||||
|
msgid "Rechtlicher Hinweis DE"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: workflows/forms.py:204
|
||||||
|
msgid "Rechtlicher Hinweis EN"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: workflows/forms.py:205
|
||||||
msgid "Standardsprache"
|
msgid "Standardsprache"
|
||||||
msgstr "Default language"
|
msgstr "Default language"
|
||||||
|
|
||||||
#: workflows/forms.py:193
|
#: workflows/forms.py:206
|
||||||
msgid "Logo"
|
msgid "Logo"
|
||||||
msgstr "Logo"
|
msgstr "Logo"
|
||||||
|
|
||||||
#: workflows/forms.py:194
|
#: workflows/forms.py:207
|
||||||
msgid "PDF-Briefkopf"
|
msgid "PDF-Briefkopf"
|
||||||
msgstr "PDF letterhead"
|
msgstr "PDF letterhead"
|
||||||
|
|
||||||
#: workflows/forms.py:195
|
#: workflows/forms.py:208
|
||||||
|
msgid "Favicon"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: workflows/forms.py:209
|
||||||
msgid "Primärfarbe"
|
msgid "Primärfarbe"
|
||||||
msgstr "Primary color"
|
msgstr "Primary color"
|
||||||
|
|
||||||
#: workflows/forms.py:196
|
#: workflows/forms.py:210
|
||||||
msgid "Sekundärfarbe"
|
msgid "Sekundärfarbe"
|
||||||
msgstr "Secondary color"
|
msgstr "Secondary color"
|
||||||
|
|
||||||
#: workflows/forms.py:210
|
#: workflows/forms.py:227
|
||||||
msgid "Das Logo darf maximal 5 MB groß sein."
|
msgid "Das Logo darf maximal 5 MB groß sein."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: workflows/forms.py:218
|
#: workflows/forms.py:235
|
||||||
msgid "Der PDF-Briefkopf darf maximal 10 MB groß sein."
|
msgid "Der PDF-Briefkopf darf maximal 10 MB groß sein."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: workflows/forms.py:357 workflows/forms.py:542
|
#: workflows/forms.py:243
|
||||||
|
msgid "Das Favicon darf maximal 2 MB groß sein."
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: workflows/forms.py:382 workflows/forms.py:567
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid "Bitte nutzen Sie das Format name@%(domain)s."
|
msgid "Bitte nutzen Sie das Format name@%(domain)s."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: workflows/forms.py:379 workflows/forms.py:556
|
#: workflows/forms.py:404 workflows/forms.py:581
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid "Bitte verwenden Sie eine @%(domain)s E-Mail-Adresse."
|
msgid "Bitte verwenden Sie eine @%(domain)s E-Mail-Adresse."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: workflows/forms.py:464
|
#: workflows/forms.py:489
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid ""
|
msgid ""
|
||||||
"Das Übergabedatum muss mindestens %(days)s Tage in der Zukunft liegen "
|
"Das Übergabedatum muss mindestens %(days)s Tage in der Zukunft liegen "
|
||||||
"(frühestens %(date)s)."
|
"(frühestens %(date)s)."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: workflows/models.py:139 workflows/views.py:200
|
#: workflows/models.py:151 workflows/views.py:200
|
||||||
msgid "Eingereicht"
|
msgid "Eingereicht"
|
||||||
msgstr "Submitted"
|
msgstr "Submitted"
|
||||||
|
|
||||||
#: workflows/models.py:140 workflows/views.py:201
|
#: workflows/models.py:152 workflows/views.py:201
|
||||||
msgid "In Bearbeitung"
|
msgid "In Bearbeitung"
|
||||||
msgstr "Processing"
|
msgstr "Processing"
|
||||||
|
|
||||||
#: workflows/models.py:141 workflows/models.py:456 workflows/views.py:202
|
#: workflows/models.py:153 workflows/models.py:468 workflows/views.py:202
|
||||||
msgid "Abgeschlossen"
|
msgid "Abgeschlossen"
|
||||||
msgstr "Completed"
|
msgstr "Completed"
|
||||||
|
|
||||||
#: workflows/models.py:142 workflows/models.py:396
|
#: workflows/models.py:154 workflows/models.py:408
|
||||||
#: workflows/templates/workflows/backup_recovery.html:70
|
#: workflows/templates/workflows/backup_recovery.html:70
|
||||||
#: workflows/templates/workflows/requests_dashboard.html:222
|
#: workflows/templates/workflows/requests_dashboard.html:222
|
||||||
#: workflows/templates/workflows/welcome_emails.html:108 workflows/views.py:203
|
#: workflows/templates/workflows/welcome_emails.html:108 workflows/views.py:203
|
||||||
msgid "Fehlgeschlagen"
|
msgid "Fehlgeschlagen"
|
||||||
msgstr "Failed"
|
msgstr "Failed"
|
||||||
|
|
||||||
#: workflows/models.py:149
|
#: workflows/models.py:161
|
||||||
msgid "Herr"
|
msgid "Herr"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: workflows/models.py:149
|
#: workflows/models.py:161
|
||||||
msgid "Frau"
|
msgid "Frau"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: workflows/models.py:149
|
#: workflows/models.py:161
|
||||||
msgid "Divers"
|
msgid "Divers"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: workflows/models.py:159
|
#: workflows/models.py:171
|
||||||
msgid "befristet"
|
msgid "befristet"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: workflows/models.py:159
|
#: workflows/models.py:171
|
||||||
msgid "unbefristet"
|
msgid "unbefristet"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: workflows/models.py:222
|
#: workflows/models.py:234
|
||||||
#: workflows/templates/workflows/onboarding_intro_session.html:28
|
#: workflows/templates/workflows/onboarding_intro_session.html:28
|
||||||
#: workflows/templates/workflows/requests_dashboard.html:145
|
#: workflows/templates/workflows/requests_dashboard.html:145
|
||||||
msgid "Abteilung"
|
msgid "Abteilung"
|
||||||
msgstr "Department"
|
msgstr "Department"
|
||||||
|
|
||||||
#: workflows/models.py:223
|
#: workflows/models.py:235
|
||||||
msgid "Geräte"
|
msgid "Geräte"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: workflows/models.py:224
|
#: workflows/models.py:236
|
||||||
msgid "Software"
|
msgid "Software"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: workflows/models.py:225
|
#: workflows/models.py:237
|
||||||
#, fuzzy
|
#, fuzzy
|
||||||
#| msgid "Vorgänge"
|
#| msgid "Vorgänge"
|
||||||
msgid "Zugänge"
|
msgid "Zugänge"
|
||||||
msgstr "Requests"
|
msgstr "Requests"
|
||||||
|
|
||||||
#: workflows/models.py:226
|
#: workflows/models.py:238
|
||||||
msgid "Workspace-Gruppen"
|
msgid "Workspace-Gruppen"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: workflows/models.py:227
|
#: workflows/models.py:239
|
||||||
msgid "Ressourcen"
|
msgid "Ressourcen"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: workflows/models.py:228
|
#: workflows/models.py:240
|
||||||
msgid "Telefonnummern"
|
msgid "Telefonnummern"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: workflows/models.py:254
|
#: workflows/models.py:266
|
||||||
msgid "Automatisch"
|
msgid "Automatisch"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: workflows/models.py:255 workflows/views.py:95
|
#: workflows/models.py:267 workflows/views.py:95
|
||||||
msgid "Stammdaten"
|
msgid "Stammdaten"
|
||||||
msgstr "Master data"
|
msgstr "Master data"
|
||||||
|
|
||||||
#: workflows/models.py:256 workflows/views.py:96
|
#: workflows/models.py:268 workflows/views.py:96
|
||||||
msgid "Vertrag"
|
msgid "Vertrag"
|
||||||
msgstr "Contract"
|
msgstr "Contract"
|
||||||
|
|
||||||
#: workflows/models.py:257 workflows/views.py:97
|
#: workflows/models.py:269 workflows/views.py:97
|
||||||
msgid "IT-Setup"
|
msgid "IT-Setup"
|
||||||
msgstr "IT setup"
|
msgstr "IT setup"
|
||||||
|
|
||||||
#: workflows/models.py:258 workflows/views.py:98
|
#: workflows/models.py:270 workflows/views.py:98
|
||||||
msgid "Abschluss"
|
msgid "Abschluss"
|
||||||
msgstr "Finish"
|
msgstr "Finish"
|
||||||
|
|
||||||
#: workflows/models.py:300
|
#: workflows/models.py:312
|
||||||
#, fuzzy
|
#, fuzzy
|
||||||
#| msgid "Onboarding"
|
#| msgid "Onboarding"
|
||||||
msgid "Onboarding: IT"
|
msgid "Onboarding: IT"
|
||||||
msgstr "Onboarding"
|
msgstr "Onboarding"
|
||||||
|
|
||||||
#: workflows/models.py:301
|
#: workflows/models.py:313
|
||||||
#, fuzzy
|
#, fuzzy
|
||||||
#| msgid "Offboarding-Anfrage speichern"
|
#| msgid "Offboarding-Anfrage speichern"
|
||||||
msgid "Onboarding: Allgemeine Info"
|
msgid "Onboarding: Allgemeine Info"
|
||||||
msgstr "Save offboarding request"
|
msgstr "Save offboarding request"
|
||||||
|
|
||||||
#: workflows/models.py:302
|
#: workflows/models.py:314
|
||||||
#, fuzzy
|
#, fuzzy
|
||||||
#| msgid "Onboarding starten"
|
#| msgid "Onboarding starten"
|
||||||
msgid "Onboarding: Visitenkarte"
|
msgid "Onboarding: Visitenkarte"
|
||||||
msgstr "Start onboarding"
|
msgstr "Start onboarding"
|
||||||
|
|
||||||
#: workflows/models.py:303
|
#: workflows/models.py:315
|
||||||
#, fuzzy
|
#, fuzzy
|
||||||
#| msgid "Onboarding"
|
#| msgid "Onboarding"
|
||||||
msgid "Onboarding: HR Works"
|
msgid "Onboarding: HR Works"
|
||||||
msgstr "Onboarding"
|
msgstr "Onboarding"
|
||||||
|
|
||||||
#: workflows/models.py:304
|
#: workflows/models.py:316
|
||||||
#, fuzzy
|
#, fuzzy
|
||||||
#| msgid "Onboarding starten"
|
#| msgid "Onboarding starten"
|
||||||
msgid "Onboarding: Schlüssel"
|
msgid "Onboarding: Schlüssel"
|
||||||
msgstr "Start onboarding"
|
msgstr "Start onboarding"
|
||||||
|
|
||||||
#: workflows/models.py:305
|
#: workflows/models.py:317
|
||||||
msgid "Onboarding: Referenz Anfordernde Person"
|
msgid "Onboarding: Referenz Anfordernde Person"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: workflows/models.py:306
|
#: workflows/models.py:318
|
||||||
#, fuzzy
|
#, fuzzy
|
||||||
#| msgid "Welcome E-Mails"
|
#| msgid "Welcome E-Mails"
|
||||||
msgid "Onboarding: Welcome E-Mail"
|
msgid "Onboarding: Welcome E-Mail"
|
||||||
msgstr "Welcome Emails"
|
msgstr "Welcome Emails"
|
||||||
|
|
||||||
#: workflows/models.py:307
|
#: workflows/models.py:319
|
||||||
#, fuzzy
|
#, fuzzy
|
||||||
#| msgid "Offboarding"
|
#| msgid "Offboarding"
|
||||||
msgid "Offboarding: IT"
|
msgid "Offboarding: IT"
|
||||||
msgstr "Offboarding"
|
msgstr "Offboarding"
|
||||||
|
|
||||||
#: workflows/models.py:308
|
#: workflows/models.py:320
|
||||||
#, fuzzy
|
#, fuzzy
|
||||||
#| msgid "Offboarding-Anfrage speichern"
|
#| msgid "Offboarding-Anfrage speichern"
|
||||||
msgid "Offboarding: Allgemeine Info"
|
msgid "Offboarding: Allgemeine Info"
|
||||||
msgstr "Save offboarding request"
|
msgstr "Save offboarding request"
|
||||||
|
|
||||||
#: workflows/models.py:309
|
#: workflows/models.py:321
|
||||||
#, fuzzy
|
#, fuzzy
|
||||||
#| msgid "Offboarding starten"
|
#| msgid "Offboarding starten"
|
||||||
msgid "Offboarding: HR Works Deaktivierung"
|
msgid "Offboarding: HR Works Deaktivierung"
|
||||||
msgstr "Start offboarding"
|
msgstr "Start offboarding"
|
||||||
|
|
||||||
#: workflows/models.py:310
|
#: workflows/models.py:322
|
||||||
msgid "Offboarding: Referenz Anfordernde Person"
|
msgid "Offboarding: Referenz Anfordernde Person"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: workflows/models.py:346
|
#: workflows/models.py:358
|
||||||
msgid "Immer"
|
msgid "Immer"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: workflows/models.py:347 workflows/models.py:425
|
#: workflows/models.py:359 workflows/models.py:437
|
||||||
msgid "Enthält"
|
msgid "Enthält"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: workflows/models.py:348 workflows/models.py:426
|
#: workflows/models.py:360 workflows/models.py:438
|
||||||
msgid "Ist gleich"
|
msgid "Ist gleich"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: workflows/models.py:349
|
#: workflows/models.py:361
|
||||||
msgid "Ist aktiv/Ja"
|
msgid "Ist aktiv/Ja"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: workflows/models.py:350
|
#: workflows/models.py:362
|
||||||
#, fuzzy
|
#, fuzzy
|
||||||
#| msgid "inaktiv"
|
#| msgid "inaktiv"
|
||||||
msgid "Ist inaktiv/Nein"
|
msgid "Ist inaktiv/Nein"
|
||||||
msgstr "inactive"
|
msgstr "inactive"
|
||||||
|
|
||||||
#: workflows/models.py:392
|
#: workflows/models.py:404
|
||||||
#: workflows/templates/workflows/welcome_emails.html:100
|
#: workflows/templates/workflows/welcome_emails.html:100
|
||||||
msgid "Geplant"
|
msgid "Geplant"
|
||||||
msgstr "Scheduled"
|
msgstr "Scheduled"
|
||||||
|
|
||||||
#: workflows/models.py:393
|
#: workflows/models.py:405
|
||||||
#: workflows/templates/workflows/welcome_emails.html:102
|
#: workflows/templates/workflows/welcome_emails.html:102
|
||||||
msgid "Pausiert"
|
msgid "Pausiert"
|
||||||
msgstr "Paused"
|
msgstr "Paused"
|
||||||
|
|
||||||
#: workflows/models.py:394
|
#: workflows/models.py:406
|
||||||
#: workflows/templates/workflows/welcome_emails.html:104
|
#: workflows/templates/workflows/welcome_emails.html:104
|
||||||
msgid "Abgebrochen"
|
msgid "Abgebrochen"
|
||||||
msgstr "Cancelled"
|
msgstr "Cancelled"
|
||||||
|
|
||||||
#: workflows/models.py:395
|
#: workflows/models.py:407
|
||||||
#: workflows/templates/workflows/welcome_emails.html:106
|
#: workflows/templates/workflows/welcome_emails.html:106
|
||||||
msgid "Gesendet"
|
msgid "Gesendet"
|
||||||
msgstr "Sent"
|
msgstr "Sent"
|
||||||
|
|
||||||
#: workflows/models.py:418 workflows/tasks.py:576
|
#: workflows/models.py:430 workflows/tasks.py:576
|
||||||
msgid "Geräte und Arbeitsplatz"
|
msgid "Geräte und Arbeitsplatz"
|
||||||
msgstr "Devices and workplace"
|
msgstr "Devices and workplace"
|
||||||
|
|
||||||
#: workflows/models.py:419 workflows/tasks.py:577
|
#: workflows/models.py:431 workflows/tasks.py:577
|
||||||
msgid "Konten und Berechtigungen"
|
msgid "Konten und Berechtigungen"
|
||||||
msgstr "Accounts and permissions"
|
msgstr "Accounts and permissions"
|
||||||
|
|
||||||
#: workflows/models.py:420 workflows/tasks.py:578
|
#: workflows/models.py:432 workflows/tasks.py:578
|
||||||
msgid "Software und Tools"
|
msgid "Software und Tools"
|
||||||
msgstr "Software and tools"
|
msgstr "Software and tools"
|
||||||
|
|
||||||
#: workflows/models.py:421 workflows/tasks.py:579
|
#: workflows/models.py:433 workflows/tasks.py:579
|
||||||
msgid "Prozesse und Hinweise"
|
msgid "Prozesse und Hinweise"
|
||||||
msgstr "Processes and notes"
|
msgstr "Processes and notes"
|
||||||
|
|
||||||
#: workflows/models.py:424
|
#: workflows/models.py:436
|
||||||
msgid "Immer anzeigen"
|
msgid "Immer anzeigen"
|
||||||
msgstr "Always show"
|
msgstr "Always show"
|
||||||
|
|
||||||
#: workflows/models.py:427
|
#: workflows/models.py:439
|
||||||
msgid "Ist Ja / aktiv"
|
msgid "Ist Ja / aktiv"
|
||||||
msgstr "Is yes / active"
|
msgstr "Is yes / active"
|
||||||
|
|
||||||
#: workflows/models.py:428
|
#: workflows/models.py:440
|
||||||
msgid "Ist Nein / inaktiv"
|
msgid "Ist Nein / inaktiv"
|
||||||
msgstr "Is no / inactive"
|
msgstr "Is no / inactive"
|
||||||
|
|
||||||
#: workflows/models.py:455
|
#: workflows/models.py:467
|
||||||
msgid "Entwurf"
|
msgid "Entwurf"
|
||||||
msgstr "Draft"
|
msgstr "Draft"
|
||||||
|
|
||||||
#: workflows/models.py:475
|
#: workflows/models.py:487
|
||||||
#, fuzzy
|
#, fuzzy
|
||||||
#| msgid "Nextcloud:"
|
#| msgid "Nextcloud:"
|
||||||
msgid "Nextcloud"
|
msgid "Nextcloud"
|
||||||
msgstr "Nextcloud:"
|
msgstr "Nextcloud:"
|
||||||
|
|
||||||
#: workflows/models.py:476
|
#: workflows/models.py:488
|
||||||
msgid "S3"
|
msgid "S3"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: workflows/models.py:477
|
#: workflows/models.py:489
|
||||||
msgid "NFS"
|
msgid "NFS"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
@@ -754,7 +786,6 @@ msgid "Anmeldung"
|
|||||||
msgstr "Sign in"
|
msgstr "Sign in"
|
||||||
|
|
||||||
#: workflows/templates/registration/login.html:20
|
#: workflows/templates/registration/login.html:20
|
||||||
#: workflows/templates/workflows/auth/login.html:18
|
|
||||||
msgid "Bitte melden Sie sich mit Ihrem Benutzerkonto an."
|
msgid "Bitte melden Sie sich mit Ihrem Benutzerkonto an."
|
||||||
msgstr "Please sign in with your user account."
|
msgstr "Please sign in with your user account."
|
||||||
|
|
||||||
@@ -1173,28 +1204,28 @@ msgstr "Delete"
|
|||||||
msgid "Noch keine Backup-Bundles vorhanden."
|
msgid "Noch keine Backup-Bundles vorhanden."
|
||||||
msgstr "No backup bundles available yet."
|
msgstr "No backup bundles available yet."
|
||||||
|
|
||||||
#: workflows/templates/workflows/base_shell.html:24
|
#: workflows/templates/workflows/base_shell.html:31
|
||||||
msgid "Bitte bestätigen"
|
msgid "Bitte bestätigen"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: workflows/templates/workflows/base_shell.html:28
|
#: workflows/templates/workflows/base_shell.html:35
|
||||||
#: workflows/templates/workflows/welcome_emails.html:134
|
#: workflows/templates/workflows/welcome_emails.html:134
|
||||||
msgid "Abbrechen"
|
msgid "Abbrechen"
|
||||||
msgstr "Cancel"
|
msgstr "Cancel"
|
||||||
|
|
||||||
#: workflows/templates/workflows/base_shell.html:29
|
#: workflows/templates/workflows/base_shell.html:36
|
||||||
msgid "Bestätigen"
|
msgid "Bestätigen"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: workflows/templates/workflows/base_shell.html:36
|
#: workflows/templates/workflows/base_shell.html:43
|
||||||
msgid "Bitte warten"
|
msgid "Bitte warten"
|
||||||
msgstr "Please wait"
|
msgstr "Please wait"
|
||||||
|
|
||||||
#: workflows/templates/workflows/base_shell.html:37
|
#: workflows/templates/workflows/base_shell.html:44
|
||||||
msgid "Aktion läuft"
|
msgid "Aktion läuft"
|
||||||
msgstr "Action in progress"
|
msgstr "Action in progress"
|
||||||
|
|
||||||
#: workflows/templates/workflows/base_shell.html:38
|
#: workflows/templates/workflows/base_shell.html:45
|
||||||
msgid "Die Aktion wird im aktuellen Tab ausgeführt."
|
msgid "Die Aktion wird im aktuellen Tab ausgeführt."
|
||||||
msgstr "The action is running in the current tab."
|
msgstr "The action is running in the current tab."
|
||||||
|
|
||||||
@@ -1209,28 +1240,43 @@ msgid ""
|
|||||||
"B. tub.co."
|
"B. tub.co."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: workflows/templates/workflows/branding_settings.html:53
|
#: workflows/templates/workflows/branding_settings.html:41
|
||||||
|
msgid "Wird für ausgehende System-E-Mails als Anzeigename verwendet."
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: workflows/templates/workflows/branding_settings.html:78
|
||||||
msgid "Erlaubte Formate: SVG, PNG, JPG, JPEG, WEBP. Maximal 5 MB."
|
msgid "Erlaubte Formate: SVG, PNG, JPG, JPEG, WEBP. Maximal 5 MB."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: workflows/templates/workflows/branding_settings.html:56
|
#: workflows/templates/workflows/branding_settings.html:81
|
||||||
msgid "Aktuelles Logo:"
|
msgid "Aktuelles Logo:"
|
||||||
msgstr "Current logo:"
|
msgstr "Current logo:"
|
||||||
|
|
||||||
#: workflows/templates/workflows/branding_settings.html:56
|
#: workflows/templates/workflows/branding_settings.html:81
|
||||||
#: workflows/templates/workflows/branding_settings.html:65
|
#: workflows/templates/workflows/branding_settings.html:90
|
||||||
|
#: workflows/templates/workflows/branding_settings.html:99
|
||||||
msgid "öffnen"
|
msgid "öffnen"
|
||||||
msgstr "open"
|
msgstr "open"
|
||||||
|
|
||||||
#: workflows/templates/workflows/branding_settings.html:62
|
#: workflows/templates/workflows/branding_settings.html:87
|
||||||
msgid "Erlaubtes Format: PDF. Maximal 10 MB."
|
msgid "Erlaubtes Format: PDF. Maximal 10 MB."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: workflows/templates/workflows/branding_settings.html:65
|
#: workflows/templates/workflows/branding_settings.html:90
|
||||||
msgid "Aktueller Briefkopf:"
|
msgid "Aktueller Briefkopf:"
|
||||||
msgstr "Current letterhead:"
|
msgstr "Current letterhead:"
|
||||||
|
|
||||||
#: workflows/templates/workflows/branding_settings.html:70
|
#: workflows/templates/workflows/branding_settings.html:96
|
||||||
|
msgid "Erlaubte Formate: ICO, PNG, SVG, WEBP. Maximal 2 MB."
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: workflows/templates/workflows/branding_settings.html:99
|
||||||
|
#, fuzzy
|
||||||
|
#| msgid "Aktuelles Logo:"
|
||||||
|
msgid "Aktuelles Favicon:"
|
||||||
|
msgstr "Current logo:"
|
||||||
|
|
||||||
|
#: workflows/templates/workflows/branding_settings.html:104
|
||||||
msgid ""
|
msgid ""
|
||||||
"TUBCO bleibt als Standard erhalten, bis hier Werte geändert oder Dateien "
|
"TUBCO bleibt als Standard erhalten, bis hier Werte geändert oder Dateien "
|
||||||
"hochgeladen werden."
|
"hochgeladen werden."
|
||||||
@@ -1238,7 +1284,7 @@ msgstr ""
|
|||||||
"TUBCO remains the default until values are changed or files are uploaded "
|
"TUBCO remains the default until values are changed or files are uploaded "
|
||||||
"here."
|
"here."
|
||||||
|
|
||||||
#: workflows/templates/workflows/branding_settings.html:71
|
#: workflows/templates/workflows/branding_settings.html:105
|
||||||
msgid "Branding speichern"
|
msgid "Branding speichern"
|
||||||
msgstr "Save branding"
|
msgstr "Save branding"
|
||||||
|
|
||||||
|
|||||||
@@ -22,7 +22,7 @@ class AdminAuditLogAdmin(admin.ModelAdmin):
|
|||||||
|
|
||||||
@admin.register(PortalBranding)
|
@admin.register(PortalBranding)
|
||||||
class PortalBrandingAdmin(admin.ModelAdmin):
|
class PortalBrandingAdmin(admin.ModelAdmin):
|
||||||
list_display = ('name', 'portal_title', 'company_name', 'support_email', 'default_language', 'updated_at')
|
list_display = ('name', 'portal_title', 'company_name', 'company_domain', 'support_email', 'default_language', 'updated_at')
|
||||||
|
|
||||||
|
|
||||||
@admin.register(PortalAppConfig)
|
@admin.register(PortalAppConfig)
|
||||||
|
|||||||
@@ -1,9 +1,11 @@
|
|||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
from email.utils import formataddr
|
||||||
|
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
from django.templatetags.static import static
|
from django.templatetags.static import static
|
||||||
|
from django.utils.translation import get_language
|
||||||
|
|
||||||
from .models import PortalBranding
|
from .models import PortalBranding
|
||||||
|
|
||||||
@@ -16,6 +18,12 @@ def get_portal_branding() -> PortalBranding:
|
|||||||
'company_name': 'TUBCO',
|
'company_name': 'TUBCO',
|
||||||
'company_domain': 'tub.co',
|
'company_domain': 'tub.co',
|
||||||
'support_email': 'info@tub.co',
|
'support_email': 'info@tub.co',
|
||||||
|
'sender_display_name': 'TUBCO',
|
||||||
|
'login_subtitle': 'Bitte melden Sie sich mit Ihrem Benutzerkonto an.',
|
||||||
|
'footer_text': 'TUBCO Onboarding & Offboarding Portal',
|
||||||
|
'footer_text_en': 'TUBCO Onboarding & Offboarding Portal',
|
||||||
|
'legal_notice': '',
|
||||||
|
'legal_notice_en': '',
|
||||||
'default_language': 'de',
|
'default_language': 'de',
|
||||||
'primary_color': '#000078',
|
'primary_color': '#000078',
|
||||||
'secondary_color': '#c0002b',
|
'secondary_color': '#c0002b',
|
||||||
@@ -40,6 +48,16 @@ def get_portal_logo_url() -> str:
|
|||||||
return static('workflows/img/tubco-logo.svg')
|
return static('workflows/img/tubco-logo.svg')
|
||||||
|
|
||||||
|
|
||||||
|
def get_portal_favicon_url() -> str:
|
||||||
|
branding = get_portal_branding()
|
||||||
|
if branding.favicon_image:
|
||||||
|
try:
|
||||||
|
return branding.favicon_image.url
|
||||||
|
except ValueError:
|
||||||
|
pass
|
||||||
|
return static('workflows/img/tubco-logo.svg')
|
||||||
|
|
||||||
|
|
||||||
def get_portal_letterhead_path() -> Path:
|
def get_portal_letterhead_path() -> Path:
|
||||||
branding = get_portal_branding()
|
branding = get_portal_branding()
|
||||||
if branding.pdf_letterhead:
|
if branding.pdf_letterhead:
|
||||||
@@ -54,18 +72,31 @@ def get_portal_letterhead_path() -> Path:
|
|||||||
|
|
||||||
def get_branding_context() -> dict[str, object]:
|
def get_branding_context() -> dict[str, object]:
|
||||||
branding = get_portal_branding()
|
branding = get_portal_branding()
|
||||||
|
lang = (get_language() or branding.default_language or 'de').split('-')[0]
|
||||||
|
footer_text = (branding.footer_text_en or '').strip() if lang == 'en' else ''
|
||||||
|
legal_notice = (branding.legal_notice_en or '').strip() if lang == 'en' else ''
|
||||||
|
if not footer_text:
|
||||||
|
footer_text = (branding.footer_text or branding.portal_title).strip()
|
||||||
|
if not legal_notice:
|
||||||
|
legal_notice = (branding.legal_notice or '').strip()
|
||||||
return {
|
return {
|
||||||
'portal_branding': branding,
|
'portal_branding': branding,
|
||||||
'portal_title': branding.portal_title,
|
'portal_title': branding.portal_title,
|
||||||
'portal_company_name': branding.company_name,
|
'portal_company_name': branding.company_name,
|
||||||
'portal_email_domain': get_company_email_domain(),
|
'portal_email_domain': get_company_email_domain(),
|
||||||
'portal_support_email': branding.support_email,
|
'portal_support_email': branding.support_email,
|
||||||
|
'portal_sender_display_name': branding.sender_display_name or branding.company_name,
|
||||||
|
'portal_login_subtitle': branding.login_subtitle,
|
||||||
|
'portal_footer_text': footer_text,
|
||||||
|
'portal_legal_notice': legal_notice,
|
||||||
'portal_default_language': branding.default_language,
|
'portal_default_language': branding.default_language,
|
||||||
'portal_primary_color': branding.primary_color,
|
'portal_primary_color': branding.primary_color,
|
||||||
'portal_secondary_color': branding.secondary_color,
|
'portal_secondary_color': branding.secondary_color,
|
||||||
'portal_logo_url': get_portal_logo_url(),
|
'portal_logo_url': get_portal_logo_url(),
|
||||||
|
'portal_favicon_url': get_portal_favicon_url(),
|
||||||
'portal_has_custom_logo': bool(branding.logo_image),
|
'portal_has_custom_logo': bool(branding.logo_image),
|
||||||
'portal_has_custom_letterhead': bool(branding.pdf_letterhead),
|
'portal_has_custom_letterhead': bool(branding.pdf_letterhead),
|
||||||
|
'portal_has_custom_favicon': bool(branding.favicon_image),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -78,9 +109,20 @@ def get_branding_email_copy() -> dict[str, str]:
|
|||||||
'company_domain': get_company_email_domain(),
|
'company_domain': get_company_email_domain(),
|
||||||
'portal_title': portal_title,
|
'portal_title': portal_title,
|
||||||
'support_email': (branding.support_email or '').strip(),
|
'support_email': (branding.support_email or '').strip(),
|
||||||
|
'sender_display_name': (branding.sender_display_name or company_name).strip(),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
def get_branded_from_email(email_address: str | None) -> str | None:
|
||||||
|
address = (email_address or '').strip()
|
||||||
|
if not address:
|
||||||
|
return None
|
||||||
|
display_name = (get_branding_email_copy()['sender_display_name'] or '').strip()
|
||||||
|
if not display_name:
|
||||||
|
return address
|
||||||
|
return formataddr((display_name, address))
|
||||||
|
|
||||||
|
|
||||||
def get_default_notification_templates() -> dict[str, dict[str, str]]:
|
def get_default_notification_templates() -> dict[str, dict[str, str]]:
|
||||||
from copy import deepcopy
|
from copy import deepcopy
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
from django.core.mail import EmailMessage, get_connection
|
from django.core.mail import EmailMessage, get_connection
|
||||||
|
|
||||||
|
from .branding import get_branded_from_email
|
||||||
from .models import SystemEmailConfig, WorkflowConfig
|
from .models import SystemEmailConfig, WorkflowConfig
|
||||||
|
|
||||||
|
|
||||||
@@ -66,7 +67,7 @@ def send_system_email(
|
|||||||
msg = EmailMessage(
|
msg = EmailMessage(
|
||||||
subject=subject,
|
subject=subject,
|
||||||
body=body,
|
body=body,
|
||||||
from_email=(from_email or smtp['from_email']),
|
from_email=get_branded_from_email(from_email or smtp['from_email']) or (from_email or smtp['from_email']),
|
||||||
to=to,
|
to=to,
|
||||||
connection=connection,
|
connection=connection,
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -178,9 +178,16 @@ class PortalBrandingForm(forms.ModelForm):
|
|||||||
'company_name',
|
'company_name',
|
||||||
'company_domain',
|
'company_domain',
|
||||||
'support_email',
|
'support_email',
|
||||||
|
'sender_display_name',
|
||||||
|
'login_subtitle',
|
||||||
|
'footer_text',
|
||||||
|
'footer_text_en',
|
||||||
|
'legal_notice',
|
||||||
|
'legal_notice_en',
|
||||||
'default_language',
|
'default_language',
|
||||||
'logo_image',
|
'logo_image',
|
||||||
'pdf_letterhead',
|
'pdf_letterhead',
|
||||||
|
'favicon_image',
|
||||||
'primary_color',
|
'primary_color',
|
||||||
'secondary_color',
|
'secondary_color',
|
||||||
]
|
]
|
||||||
@@ -189,9 +196,16 @@ class PortalBrandingForm(forms.ModelForm):
|
|||||||
'company_name': gettext_lazy('Firmenname'),
|
'company_name': gettext_lazy('Firmenname'),
|
||||||
'company_domain': gettext_lazy('Firmen-Domain'),
|
'company_domain': gettext_lazy('Firmen-Domain'),
|
||||||
'support_email': gettext_lazy('Support-E-Mail'),
|
'support_email': gettext_lazy('Support-E-Mail'),
|
||||||
|
'sender_display_name': gettext_lazy('Absender-Anzeigename'),
|
||||||
|
'login_subtitle': gettext_lazy('Login-Untertitel'),
|
||||||
|
'footer_text': gettext_lazy('Footer-Text DE'),
|
||||||
|
'footer_text_en': gettext_lazy('Footer-Text EN'),
|
||||||
|
'legal_notice': gettext_lazy('Rechtlicher Hinweis DE'),
|
||||||
|
'legal_notice_en': gettext_lazy('Rechtlicher Hinweis EN'),
|
||||||
'default_language': gettext_lazy('Standardsprache'),
|
'default_language': gettext_lazy('Standardsprache'),
|
||||||
'logo_image': gettext_lazy('Logo'),
|
'logo_image': gettext_lazy('Logo'),
|
||||||
'pdf_letterhead': gettext_lazy('PDF-Briefkopf'),
|
'pdf_letterhead': gettext_lazy('PDF-Briefkopf'),
|
||||||
|
'favicon_image': gettext_lazy('Favicon'),
|
||||||
'primary_color': gettext_lazy('Primärfarbe'),
|
'primary_color': gettext_lazy('Primärfarbe'),
|
||||||
'secondary_color': gettext_lazy('Sekundärfarbe'),
|
'secondary_color': gettext_lazy('Sekundärfarbe'),
|
||||||
}
|
}
|
||||||
@@ -200,6 +214,9 @@ class PortalBrandingForm(forms.ModelForm):
|
|||||||
'secondary_color': forms.TextInput(attrs={'type': 'color'}),
|
'secondary_color': forms.TextInput(attrs={'type': 'color'}),
|
||||||
'logo_image': forms.ClearableFileInput(attrs={'accept': '.svg,.png,.jpg,.jpeg,.webp'}),
|
'logo_image': forms.ClearableFileInput(attrs={'accept': '.svg,.png,.jpg,.jpeg,.webp'}),
|
||||||
'pdf_letterhead': forms.ClearableFileInput(attrs={'accept': '.pdf'}),
|
'pdf_letterhead': forms.ClearableFileInput(attrs={'accept': '.pdf'}),
|
||||||
|
'favicon_image': forms.ClearableFileInput(attrs={'accept': '.ico,.png,.svg,.webp'}),
|
||||||
|
'legal_notice': forms.Textarea(attrs={'rows': 3}),
|
||||||
|
'legal_notice_en': forms.Textarea(attrs={'rows': 3}),
|
||||||
}
|
}
|
||||||
|
|
||||||
def clean_logo_image(self):
|
def clean_logo_image(self):
|
||||||
@@ -218,6 +235,14 @@ class PortalBrandingForm(forms.ModelForm):
|
|||||||
raise forms.ValidationError(_('Der PDF-Briefkopf darf maximal 10 MB groß sein.'))
|
raise forms.ValidationError(_('Der PDF-Briefkopf darf maximal 10 MB groß sein.'))
|
||||||
return letterhead
|
return letterhead
|
||||||
|
|
||||||
|
def clean_favicon_image(self):
|
||||||
|
favicon = self.cleaned_data.get('favicon_image')
|
||||||
|
if not favicon:
|
||||||
|
return favicon
|
||||||
|
if getattr(favicon, 'size', 0) > 2 * 1024 * 1024:
|
||||||
|
raise forms.ValidationError(_('Das Favicon darf maximal 2 MB groß sein.'))
|
||||||
|
return favicon
|
||||||
|
|
||||||
|
|
||||||
class OnboardingRequestForm(forms.ModelForm):
|
class OnboardingRequestForm(forms.ModelForm):
|
||||||
first_name = forms.CharField(label='Vorname', required=False)
|
first_name = forms.CharField(label='Vorname', required=False)
|
||||||
|
|||||||
@@ -0,0 +1,49 @@
|
|||||||
|
# Generated by Django 5.1.5 on 2026-03-26 11:02
|
||||||
|
|
||||||
|
import django.core.validators
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('workflows', '0039_portalbranding_company_domain'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='portalbranding',
|
||||||
|
name='favicon_image',
|
||||||
|
field=models.FileField(blank=True, null=True, upload_to='branding/', validators=[django.core.validators.FileExtensionValidator(allowed_extensions=['ico', 'png', 'svg', 'webp'])]),
|
||||||
|
),
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='portalbranding',
|
||||||
|
name='footer_text',
|
||||||
|
field=models.CharField(blank=True, default='TUBCO Onboarding & Offboarding Portal', max_length=255),
|
||||||
|
),
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='portalbranding',
|
||||||
|
name='footer_text_en',
|
||||||
|
field=models.CharField(blank=True, default='TUBCO Onboarding & Offboarding Portal', max_length=255),
|
||||||
|
),
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='portalbranding',
|
||||||
|
name='legal_notice',
|
||||||
|
field=models.TextField(blank=True, default=''),
|
||||||
|
),
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='portalbranding',
|
||||||
|
name='legal_notice_en',
|
||||||
|
field=models.TextField(blank=True, default=''),
|
||||||
|
),
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='portalbranding',
|
||||||
|
name='login_subtitle',
|
||||||
|
field=models.CharField(blank=True, default='Bitte melden Sie sich mit Ihrem Benutzerkonto an.', max_length=255),
|
||||||
|
),
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='portalbranding',
|
||||||
|
name='sender_display_name',
|
||||||
|
field=models.CharField(blank=True, default='TUBCO', max_length=255),
|
||||||
|
),
|
||||||
|
]
|
||||||
@@ -31,6 +31,12 @@ class PortalBranding(models.Model):
|
|||||||
company_name = models.CharField(max_length=255, default='TUBCO')
|
company_name = models.CharField(max_length=255, default='TUBCO')
|
||||||
company_domain = models.CharField(max_length=120, blank=True, default='tub.co')
|
company_domain = models.CharField(max_length=120, blank=True, default='tub.co')
|
||||||
support_email = models.EmailField(blank=True, default='info@tub.co')
|
support_email = models.EmailField(blank=True, default='info@tub.co')
|
||||||
|
sender_display_name = models.CharField(max_length=255, blank=True, default='TUBCO')
|
||||||
|
login_subtitle = models.CharField(max_length=255, blank=True, default='Bitte melden Sie sich mit Ihrem Benutzerkonto an.')
|
||||||
|
footer_text = models.CharField(max_length=255, blank=True, default='TUBCO Onboarding & Offboarding Portal')
|
||||||
|
footer_text_en = models.CharField(max_length=255, blank=True, default='TUBCO Onboarding & Offboarding Portal')
|
||||||
|
legal_notice = models.TextField(blank=True, default='')
|
||||||
|
legal_notice_en = models.TextField(blank=True, default='')
|
||||||
default_language = models.CharField(
|
default_language = models.CharField(
|
||||||
max_length=10,
|
max_length=10,
|
||||||
choices=[('de', 'Deutsch'), ('en', 'English')],
|
choices=[('de', 'Deutsch'), ('en', 'English')],
|
||||||
@@ -48,6 +54,12 @@ class PortalBranding(models.Model):
|
|||||||
null=True,
|
null=True,
|
||||||
validators=[FileExtensionValidator(allowed_extensions=['pdf'])],
|
validators=[FileExtensionValidator(allowed_extensions=['pdf'])],
|
||||||
)
|
)
|
||||||
|
favicon_image = models.FileField(
|
||||||
|
upload_to='branding/',
|
||||||
|
blank=True,
|
||||||
|
null=True,
|
||||||
|
validators=[FileExtensionValidator(allowed_extensions=['ico', 'png', 'svg', 'webp'])],
|
||||||
|
)
|
||||||
primary_color = models.CharField(max_length=20, blank=True, default='#000078')
|
primary_color = models.CharField(max_length=20, blank=True, default='#000078')
|
||||||
secondary_color = models.CharField(max_length=20, blank=True, default='#c0002b')
|
secondary_color = models.CharField(max_length=20, blank=True, default='#c0002b')
|
||||||
updated_at = models.DateTimeField(auto_now=True)
|
updated_at = models.DateTimeField(auto_now=True)
|
||||||
|
|||||||
@@ -7,6 +7,30 @@ h1 { margin: 12px 0 6px; color: #000078; }
|
|||||||
.app-messages { margin-bottom: 12px; }
|
.app-messages { margin-bottom: 12px; }
|
||||||
.card { border: 1px solid #d8e3f0; border-radius: 12px; background: #fbfdff; padding: 12px; margin-bottom: 14px; transition: border-color 180ms cubic-bezier(0.2, 0.8, 0.2, 1), box-shadow 220ms cubic-bezier(0.2, 0.8, 0.2, 1), transform 220ms cubic-bezier(0.2, 0.8, 0.2, 1); }
|
.card { border: 1px solid #d8e3f0; border-radius: 12px; background: #fbfdff; padding: 12px; margin-bottom: 14px; transition: border-color 180ms cubic-bezier(0.2, 0.8, 0.2, 1), box-shadow 220ms cubic-bezier(0.2, 0.8, 0.2, 1), transform 220ms cubic-bezier(0.2, 0.8, 0.2, 1); }
|
||||||
.grid { display: grid; grid-template-columns: repeat(2, minmax(240px, 1fr)); gap: 10px; }
|
.grid { display: grid; grid-template-columns: repeat(2, minmax(240px, 1fr)); gap: 10px; }
|
||||||
|
.branding-sections { display: grid; gap: 14px; }
|
||||||
|
.branding-block { border: 1px solid #dce5f1; border-radius: 16px; background: linear-gradient(180deg, rgba(255,255,255,0.98), rgba(246,250,255,0.94)); padding: 14px; box-shadow: inset 0 1px 0 rgba(255,255,255,0.92); }
|
||||||
|
.branding-block-head { margin-bottom: 12px; }
|
||||||
|
.branding-block-head h2 { margin: 0; color: #17345e; font-size: 18px; }
|
||||||
|
.branding-block-head p { margin: 4px 0 0; color: #60738d; font-size: 13px; }
|
||||||
|
.lang-pairs { align-items: start; }
|
||||||
|
.lang-block { border: 1px solid #d9e4f1; border-radius: 14px; background: rgba(255,255,255,0.82); padding: 12px; }
|
||||||
|
.lang-block h3 { margin: 0 0 10px; color: #223b63; font-size: 15px; }
|
||||||
|
.branding-preview { max-width: 460px; margin-left: auto; border: 1px solid #dce5f1; border-radius: 18px; background:
|
||||||
|
radial-gradient(circle at top right, rgba(59,112,234,0.10), transparent 30%),
|
||||||
|
linear-gradient(180deg, #f9fbff, #eef4ff);
|
||||||
|
padding: 10px; }
|
||||||
|
.branding-preview-shell { border: 1px solid rgba(210, 221, 236, 0.95); border-radius: 18px; overflow: hidden; background: linear-gradient(180deg, rgba(255,255,255,0.99), rgba(247,250,255,0.96)); box-shadow: 0 8px 22px rgba(16, 32, 57, 0.05); }
|
||||||
|
.branding-preview-header { display: flex; align-items: center; gap: 10px; padding: 10px 12px; border-bottom: 1px solid rgba(217, 227, 238, 0.9); }
|
||||||
|
.branding-preview-logo { width: 64px; max-width: 100%; height: auto; display: block; object-fit: contain; filter: saturate(1.02); }
|
||||||
|
.branding-preview-copy { display: grid; gap: 2px; min-width: 0; }
|
||||||
|
.branding-preview-copy strong { color: #18335b; font-size: 13px; line-height: 1.2; }
|
||||||
|
.branding-preview-copy span { color: #61738d; font-size: 12px; line-height: 1.3; }
|
||||||
|
.branding-preview-band { display: flex; gap: 8px; padding: 10px 12px; }
|
||||||
|
.branding-preview-chip { display: inline-flex; align-items: center; justify-content: center; min-width: 104px; padding: 5px 10px; border-radius: 999px; color: #fff; font-size: 10px; font-weight: 800; letter-spacing: 0.04em; text-transform: uppercase; background: #000078; box-shadow: inset 0 1px 0 rgba(255,255,255,0.16); }
|
||||||
|
.branding-preview-chip-secondary { background: #c0002b; }
|
||||||
|
.branding-preview-footer { padding: 0 12px 12px; }
|
||||||
|
.branding-preview-footer-main { color: #20385f; font-size: 11px; font-weight: 700; line-height: 1.35; }
|
||||||
|
.branding-preview-footer-legal { margin-top: 4px; color: #6c7f99; font-size: 10px; line-height: 1.4; }
|
||||||
.backup-grid { grid-template-columns: minmax(280px, 720px); }
|
.backup-grid { grid-template-columns: minmax(280px, 720px); }
|
||||||
label { display: block; margin-bottom: 4px; font-size: 12px; color: #334155; font-weight: 700; }
|
label { display: block; margin-bottom: 4px; font-size: 12px; color: #334155; font-weight: 700; }
|
||||||
input, select, textarea { width: 100%; box-sizing: border-box; border: 1px solid #cbd5e1; border-radius: 8px; padding: 8px 9px; background: #fff; transition: border-color 180ms cubic-bezier(0.2, 0.8, 0.2, 1), box-shadow 180ms cubic-bezier(0.2, 0.8, 0.2, 1), background-color 180ms cubic-bezier(0.2, 0.8, 0.2, 1); }
|
input, select, textarea { width: 100%; box-sizing: border-box; border: 1px solid #cbd5e1; border-radius: 8px; padding: 8px 9px; background: #fff; transition: border-color 180ms cubic-bezier(0.2, 0.8, 0.2, 1), box-shadow 180ms cubic-bezier(0.2, 0.8, 0.2, 1), background-color 180ms cubic-bezier(0.2, 0.8, 0.2, 1); }
|
||||||
@@ -56,8 +80,13 @@ th { background: #f6f9ff; color: #334155; }
|
|||||||
.bulk-note { color: #64748b; font-size: 12px; }
|
.bulk-note { color: #64748b; font-size: 12px; }
|
||||||
.field label { display: block; font-weight: 600; margin-bottom: 6px; }
|
.field label { display: block; font-weight: 600; margin-bottom: 6px; }
|
||||||
.field input, .field select { min-height: 40px; }
|
.field input, .field select { min-height: 40px; }
|
||||||
|
.field-full { grid-column: 1 / -1; }
|
||||||
.mini { color: #64748b; font-size: 12px; }
|
.mini { color: #64748b; font-size: 12px; }
|
||||||
.table-controls input[type="text"], .table-controls select { width: 100%; min-height: 36px; padding: 7px 9px; border: 1px solid #cfd9e8; border-radius: 8px; box-sizing: border-box; }
|
.table-controls input[type="text"], .table-controls select { width: 100%; min-height: 36px; padding: 7px 9px; border: 1px solid #cfd9e8; border-radius: 8px; box-sizing: border-box; }
|
||||||
.table-controls input[type="checkbox"] { transform: scale(1.1); width: auto; }
|
.table-controls input[type="checkbox"] { transform: scale(1.1); width: auto; }
|
||||||
.actions { white-space: nowrap; }
|
.actions { white-space: nowrap; }
|
||||||
@media (max-width: 760px) { .grid { grid-template-columns: 1fr; } }
|
@media (max-width: 760px) {
|
||||||
|
.grid { grid-template-columns: 1fr; }
|
||||||
|
.branding-preview-header { flex-direction: column; align-items: flex-start; }
|
||||||
|
.branding-preview-band { flex-wrap: wrap; }
|
||||||
|
}
|
||||||
|
|||||||
@@ -122,6 +122,25 @@
|
|||||||
margin-right: auto !important;
|
margin-right: auto !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.app-site-footer {
|
||||||
|
width: min(var(--app-shell-width), 100%);
|
||||||
|
margin: 14px auto 0;
|
||||||
|
padding: 0 10px 18px;
|
||||||
|
color: #5f728d;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.app-site-footer-main {
|
||||||
|
font-size: 13px;
|
||||||
|
font-weight: 700;
|
||||||
|
}
|
||||||
|
|
||||||
|
.app-site-footer-legal {
|
||||||
|
margin-top: 4px;
|
||||||
|
font-size: 12px;
|
||||||
|
line-height: 1.5;
|
||||||
|
}
|
||||||
|
|
||||||
@media (max-width: 900px) {
|
@media (max-width: 900px) {
|
||||||
.app-header,
|
.app-header,
|
||||||
.app-header-in-shell {
|
.app-header-in-shell {
|
||||||
|
|||||||
@@ -15,7 +15,7 @@
|
|||||||
<section class="login-shell-body">
|
<section class="login-shell-body">
|
||||||
<div class="login-card">
|
<div class="login-card">
|
||||||
<h1>{% trans "Anmeldung" %}</h1>
|
<h1>{% trans "Anmeldung" %}</h1>
|
||||||
<p>{% trans "Bitte melden Sie sich mit Ihrem Benutzerkonto an." %}</p>
|
<p>{{ portal_login_subtitle }}</p>
|
||||||
|
|
||||||
<form method="post" action="/accounts/login/">
|
<form method="post" action="/accounts/login/">
|
||||||
{% csrf_token %}
|
{% csrf_token %}
|
||||||
|
|||||||
@@ -6,6 +6,7 @@
|
|||||||
<meta charset="utf-8" />
|
<meta charset="utf-8" />
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||||
<title>{% block title %}{% endblock %}</title>
|
<title>{% block title %}{% endblock %}</title>
|
||||||
|
<link rel="icon" href="{{ portal_favicon_url }}" />
|
||||||
<link rel="stylesheet" href="{% static 'workflows/css/buttons.css' %}" />
|
<link rel="stylesheet" href="{% static 'workflows/css/buttons.css' %}" />
|
||||||
<link rel="stylesheet" href="{% static 'workflows/css/app_chrome.css' %}" />
|
<link rel="stylesheet" href="{% static 'workflows/css/app_chrome.css' %}" />
|
||||||
{% block extra_css %}{% endblock %}
|
{% block extra_css %}{% endblock %}
|
||||||
@@ -17,6 +18,12 @@
|
|||||||
{% block shell_header %}{% endblock %}
|
{% block shell_header %}{% endblock %}
|
||||||
{% block shell_body %}{% endblock %}
|
{% block shell_body %}{% endblock %}
|
||||||
</div>
|
</div>
|
||||||
|
{% if portal_footer_text or portal_legal_notice %}
|
||||||
|
<div class="app-site-footer">
|
||||||
|
{% if portal_footer_text %}<div class="app-site-footer-main">{{ portal_footer_text }}</div>{% endif %}
|
||||||
|
{% if portal_legal_notice %}<div class="app-site-footer-legal">{{ portal_legal_notice }}</div>{% endif %}
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
<div class="confirm-modal" id="app-confirm-modal" hidden aria-hidden="true">
|
<div class="confirm-modal" id="app-confirm-modal" hidden aria-hidden="true">
|
||||||
<div class="confirm-backdrop" data-confirm-close="1"></div>
|
<div class="confirm-backdrop" data-confirm-close="1"></div>
|
||||||
<div class="confirm-dialog" role="dialog" aria-modal="true" aria-labelledby="app-confirm-title" aria-describedby="app-confirm-message">
|
<div class="confirm-dialog" role="dialog" aria-modal="true" aria-labelledby="app-confirm-title" aria-describedby="app-confirm-message">
|
||||||
|
|||||||
@@ -17,54 +17,150 @@
|
|||||||
<section class="card">
|
<section class="card">
|
||||||
<form method="post" action="{% url 'save_portal_branding' %}" enctype="multipart/form-data" class="stack-form">
|
<form method="post" action="{% url 'save_portal_branding' %}" enctype="multipart/form-data" class="stack-form">
|
||||||
{% csrf_token %}
|
{% csrf_token %}
|
||||||
<div class="grid two">
|
<div class="branding-sections">
|
||||||
<div class="field">
|
<section class="branding-block">
|
||||||
<label for="{{ form.portal_title.id_for_label }}">{{ form.portal_title.label }}</label>
|
<div class="branding-block-head">
|
||||||
{{ form.portal_title }}
|
<h2>{% trans "Identität" %}</h2>
|
||||||
</div>
|
<p>{% trans "Titel, Firmenname und zentrale Spracheinstellungen." %}</p>
|
||||||
<div class="field">
|
</div>
|
||||||
<label for="{{ form.company_name.id_for_label }}">{{ form.company_name.label }}</label>
|
<div class="grid two">
|
||||||
{{ form.company_name }}
|
<div class="field">
|
||||||
</div>
|
<label for="{{ form.portal_title.id_for_label }}">{{ form.portal_title.label }}</label>
|
||||||
<div class="field">
|
{{ form.portal_title }}
|
||||||
<label for="{{ form.company_domain.id_for_label }}">{{ form.company_domain.label }}</label>
|
</div>
|
||||||
{{ form.company_domain }}
|
<div class="field">
|
||||||
<div class="hint">{% trans "Wird für E-Mail-Vorschläge und Domain-bezogene Standardtexte verwendet, z. B. tub.co." %}</div>
|
<label for="{{ form.company_name.id_for_label }}">{{ form.company_name.label }}</label>
|
||||||
</div>
|
{{ form.company_name }}
|
||||||
<div class="field">
|
</div>
|
||||||
<label for="{{ form.support_email.id_for_label }}">{{ form.support_email.label }}</label>
|
<div class="field">
|
||||||
{{ form.support_email }}
|
<label for="{{ form.company_domain.id_for_label }}">{{ form.company_domain.label }}</label>
|
||||||
</div>
|
{{ form.company_domain }}
|
||||||
<div class="field">
|
<div class="hint">{% trans "Wird für E-Mail-Vorschläge und Domain-bezogene Standardtexte verwendet, z. B. tub.co." %}</div>
|
||||||
<label for="{{ form.default_language.id_for_label }}">{{ form.default_language.label }}</label>
|
</div>
|
||||||
{{ form.default_language }}
|
<div class="field">
|
||||||
</div>
|
<label for="{{ form.default_language.id_for_label }}">{{ form.default_language.label }}</label>
|
||||||
<div class="field">
|
{{ form.default_language }}
|
||||||
<label for="{{ form.primary_color.id_for_label }}">{{ form.primary_color.label }}</label>
|
</div>
|
||||||
{{ form.primary_color }}
|
<div class="field field-full">
|
||||||
</div>
|
<label for="{{ form.login_subtitle.id_for_label }}">{{ form.login_subtitle.label }}</label>
|
||||||
<div class="field">
|
{{ form.login_subtitle }}
|
||||||
<label for="{{ form.secondary_color.id_for_label }}">{{ form.secondary_color.label }}</label>
|
</div>
|
||||||
{{ form.secondary_color }}
|
</div>
|
||||||
</div>
|
</section>
|
||||||
<div class="field">
|
|
||||||
<label for="{{ form.logo_image.id_for_label }}">{{ form.logo_image.label }}</label>
|
<section class="branding-block">
|
||||||
{{ form.logo_image }}
|
<div class="branding-block-head">
|
||||||
<div class="hint">{% trans "Erlaubte Formate: SVG, PNG, JPG, JPEG, WEBP. Maximal 5 MB." %}</div>
|
<h2>{% trans "Farben & Erscheinungsbild" %}</h2>
|
||||||
{% for error in form.logo_image.errors %}<div class="hint">{{ error }}</div>{% endfor %}
|
<p>{% trans "Zentrale visuelle Markenwerte und Browser-Icon." %}</p>
|
||||||
{% if branding.logo_image %}
|
</div>
|
||||||
<div class="hint">{% trans "Aktuelles Logo:" %} <a href="{{ branding.logo_image.url }}" target="_blank" rel="noopener">{% trans "öffnen" %}</a></div>
|
<div class="grid two">
|
||||||
{% endif %}
|
<div class="field">
|
||||||
</div>
|
<label for="{{ form.primary_color.id_for_label }}">{{ form.primary_color.label }}</label>
|
||||||
<div class="field">
|
{{ form.primary_color }}
|
||||||
<label for="{{ form.pdf_letterhead.id_for_label }}">{{ form.pdf_letterhead.label }}</label>
|
</div>
|
||||||
{{ form.pdf_letterhead }}
|
<div class="field">
|
||||||
<div class="hint">{% trans "Erlaubtes Format: PDF. Maximal 10 MB." %}</div>
|
<label for="{{ form.secondary_color.id_for_label }}">{{ form.secondary_color.label }}</label>
|
||||||
{% for error in form.pdf_letterhead.errors %}<div class="hint">{{ error }}</div>{% endfor %}
|
{{ form.secondary_color }}
|
||||||
{% if branding.pdf_letterhead %}
|
</div>
|
||||||
<div class="hint">{% trans "Aktueller Briefkopf:" %} <a href="{{ branding.pdf_letterhead.url }}" target="_blank" rel="noopener">{% trans "öffnen" %}</a></div>
|
<div class="field">
|
||||||
{% endif %}
|
<label for="{{ form.logo_image.id_for_label }}">{{ form.logo_image.label }}</label>
|
||||||
</div>
|
{{ form.logo_image }}
|
||||||
|
<div class="hint">{% trans "Erlaubte Formate: SVG, PNG, JPG, JPEG, WEBP. Maximal 5 MB." %}</div>
|
||||||
|
{% for error in form.logo_image.errors %}<div class="hint">{{ error }}</div>{% endfor %}
|
||||||
|
{% if branding.logo_image %}
|
||||||
|
<div class="hint">{% trans "Aktuelles Logo:" %} <a href="{{ branding.logo_image.url }}" target="_blank" rel="noopener">{% trans "öffnen" %}</a></div>
|
||||||
|
{% endif %}
|
||||||
|
</div>
|
||||||
|
<div class="field">
|
||||||
|
<label for="{{ form.favicon_image.id_for_label }}">{{ form.favicon_image.label }}</label>
|
||||||
|
{{ form.favicon_image }}
|
||||||
|
<div class="hint">{% trans "Erlaubte Formate: ICO, PNG, SVG, WEBP. Maximal 2 MB." %}</div>
|
||||||
|
{% for error in form.favicon_image.errors %}<div class="hint">{{ error }}</div>{% endfor %}
|
||||||
|
{% if branding.favicon_image %}
|
||||||
|
<div class="hint">{% trans "Aktuelles Favicon:" %} <a href="{{ branding.favicon_image.url }}" target="_blank" rel="noopener">{% trans "öffnen" %}</a></div>
|
||||||
|
{% endif %}
|
||||||
|
</div>
|
||||||
|
<div class="field field-full">
|
||||||
|
<div class="branding-preview" id="branding-preview" data-default-logo="{{ portal_logo_url }}">
|
||||||
|
<div class="branding-preview-shell">
|
||||||
|
<div class="branding-preview-header">
|
||||||
|
<img class="branding-preview-logo" id="branding-preview-logo" src="{{ portal_logo_url }}" alt="{{ portal_company_name }} Logo" />
|
||||||
|
<div class="branding-preview-copy">
|
||||||
|
<strong id="branding-preview-company">{{ branding.company_name }}</strong>
|
||||||
|
<span id="branding-preview-title">{{ branding.portal_title }}</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="branding-preview-band">
|
||||||
|
<span class="branding-preview-chip" id="branding-preview-primary">{% trans "Primärfarbe" %}</span>
|
||||||
|
<span class="branding-preview-chip branding-preview-chip-secondary" id="branding-preview-secondary">{% trans "Sekundärfarbe" %}</span>
|
||||||
|
</div>
|
||||||
|
<div class="branding-preview-footer">
|
||||||
|
<div class="branding-preview-footer-main" id="branding-preview-footer">{{ branding.footer_text|default:branding.portal_title }}</div>
|
||||||
|
<div class="branding-preview-footer-legal" id="branding-preview-legal">{{ branding.legal_notice }}</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<section class="branding-block">
|
||||||
|
<div class="branding-block-head">
|
||||||
|
<h2>{% trans "Kommunikation" %}</h2>
|
||||||
|
<p>{% trans "Absender, Support und PDF-Branding für ausgehende Kommunikation." %}</p>
|
||||||
|
</div>
|
||||||
|
<div class="grid two">
|
||||||
|
<div class="field">
|
||||||
|
<label for="{{ form.support_email.id_for_label }}">{{ form.support_email.label }}</label>
|
||||||
|
{{ form.support_email }}
|
||||||
|
</div>
|
||||||
|
<div class="field">
|
||||||
|
<label for="{{ form.sender_display_name.id_for_label }}">{{ form.sender_display_name.label }}</label>
|
||||||
|
{{ form.sender_display_name }}
|
||||||
|
<div class="hint">{% trans "Wird für ausgehende System-E-Mails als Anzeigename verwendet." %}</div>
|
||||||
|
</div>
|
||||||
|
<div class="field field-full">
|
||||||
|
<label for="{{ form.pdf_letterhead.id_for_label }}">{{ form.pdf_letterhead.label }}</label>
|
||||||
|
{{ form.pdf_letterhead }}
|
||||||
|
<div class="hint">{% trans "Erlaubtes Format: PDF. Maximal 10 MB." %}</div>
|
||||||
|
{% for error in form.pdf_letterhead.errors %}<div class="hint">{{ error }}</div>{% endfor %}
|
||||||
|
{% if branding.pdf_letterhead %}
|
||||||
|
<div class="hint">{% trans "Aktueller Briefkopf:" %} <a href="{{ branding.pdf_letterhead.url }}" target="_blank" rel="noopener">{% trans "öffnen" %}</a></div>
|
||||||
|
{% endif %}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<section class="branding-block">
|
||||||
|
<div class="branding-block-head">
|
||||||
|
<h2>{% trans "Footer & Rechtliches" %}</h2>
|
||||||
|
<p>{% trans "Gemeinsame Footer-Texte und rechtliche Hinweise für die Shell." %}</p>
|
||||||
|
</div>
|
||||||
|
<div class="grid two lang-pairs">
|
||||||
|
<div class="lang-block">
|
||||||
|
<h3>{% trans "Deutsch" %}</h3>
|
||||||
|
<div class="field">
|
||||||
|
<label for="{{ form.footer_text.id_for_label }}">{{ form.footer_text.label }}</label>
|
||||||
|
{{ form.footer_text }}
|
||||||
|
</div>
|
||||||
|
<div class="field">
|
||||||
|
<label for="{{ form.legal_notice.id_for_label }}">{{ form.legal_notice.label }}</label>
|
||||||
|
{{ form.legal_notice }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="lang-block">
|
||||||
|
<h3>{% trans "English" %}</h3>
|
||||||
|
<div class="field">
|
||||||
|
<label for="{{ form.footer_text_en.id_for_label }}">{{ form.footer_text_en.label }}</label>
|
||||||
|
{{ form.footer_text_en }}
|
||||||
|
</div>
|
||||||
|
<div class="field">
|
||||||
|
<label for="{{ form.legal_notice_en.id_for_label }}">{{ form.legal_notice_en.label }}</label>
|
||||||
|
{{ form.legal_notice_en }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
</div>
|
</div>
|
||||||
<div class="toolbar" style="margin-top:1.25rem;">
|
<div class="toolbar" style="margin-top:1.25rem;">
|
||||||
<div class="hint">{% trans "TUBCO bleibt als Standard erhalten, bis hier Werte geändert oder Dateien hochgeladen werden." %}</div>
|
<div class="hint">{% trans "TUBCO bleibt als Standard erhalten, bis hier Werte geändert oder Dateien hochgeladen werden." %}</div>
|
||||||
@@ -73,3 +169,59 @@
|
|||||||
</form>
|
</form>
|
||||||
</section>
|
</section>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
|
{% block extra_scripts %}
|
||||||
|
<script>
|
||||||
|
(() => {
|
||||||
|
const byId = (id) => document.getElementById(id);
|
||||||
|
const title = byId('{{ form.portal_title.id_for_label }}');
|
||||||
|
const company = byId('{{ form.company_name.id_for_label }}');
|
||||||
|
const footer = byId('{{ form.footer_text.id_for_label }}');
|
||||||
|
const legal = byId('{{ form.legal_notice.id_for_label }}');
|
||||||
|
const primary = byId('{{ form.primary_color.id_for_label }}');
|
||||||
|
const secondary = byId('{{ form.secondary_color.id_for_label }}');
|
||||||
|
const logo = byId('{{ form.logo_image.id_for_label }}');
|
||||||
|
const previewLogo = byId('branding-preview-logo');
|
||||||
|
const previewTitle = byId('branding-preview-title');
|
||||||
|
const previewCompany = byId('branding-preview-company');
|
||||||
|
const previewFooter = byId('branding-preview-footer');
|
||||||
|
const previewLegal = byId('branding-preview-legal');
|
||||||
|
const previewPrimary = byId('branding-preview-primary');
|
||||||
|
const previewSecondary = byId('branding-preview-secondary');
|
||||||
|
const preview = byId('branding-preview');
|
||||||
|
if (!preview) return;
|
||||||
|
|
||||||
|
const defaultLogo = preview.dataset.defaultLogo || '';
|
||||||
|
|
||||||
|
function syncPreview() {
|
||||||
|
if (previewTitle && title) previewTitle.textContent = title.value || '{{ branding.portal_title|escapejs }}';
|
||||||
|
if (previewCompany && company) previewCompany.textContent = company.value || '{{ branding.company_name|escapejs }}';
|
||||||
|
if (previewFooter && footer) previewFooter.textContent = footer.value || '{{ branding.footer_text|default:branding.portal_title|escapejs }}';
|
||||||
|
if (previewLegal && legal) previewLegal.textContent = legal.value || '{{ branding.legal_notice|escapejs }}';
|
||||||
|
if (previewPrimary && primary) previewPrimary.style.background = primary.value || '#000078';
|
||||||
|
if (previewSecondary && secondary) previewSecondary.style.background = secondary.value || '#c0002b';
|
||||||
|
}
|
||||||
|
|
||||||
|
[title, company, footer, legal, primary, secondary].forEach((input) => {
|
||||||
|
if (input) input.addEventListener('input', syncPreview);
|
||||||
|
});
|
||||||
|
|
||||||
|
if (logo && previewLogo) {
|
||||||
|
logo.addEventListener('change', () => {
|
||||||
|
const file = logo.files && logo.files[0];
|
||||||
|
if (!file) {
|
||||||
|
previewLogo.src = defaultLogo;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const reader = new FileReader();
|
||||||
|
reader.onload = (event) => {
|
||||||
|
previewLogo.src = event.target.result;
|
||||||
|
};
|
||||||
|
reader.readAsDataURL(file);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
syncPreview();
|
||||||
|
})();
|
||||||
|
</script>
|
||||||
|
{% endblock %}
|
||||||
|
|||||||
@@ -176,8 +176,10 @@ docker compose exec -T web django-admin compilemessages</code></pre>
|
|||||||
<ul>
|
<ul>
|
||||||
<li>Portal-level branding is stored in the singleton model <code>PortalBranding</code>.</li>
|
<li>Portal-level branding is stored in the singleton model <code>PortalBranding</code>.</li>
|
||||||
<li>Configured from Admin Apps → <code>Branding</code>.</li>
|
<li>Configured from Admin Apps → <code>Branding</code>.</li>
|
||||||
<li>Current scope: portal title, company name, support email, default language, logo, PDF letterhead, and primary/secondary colors.</li>
|
<li>Current scope: portal title, company name, company domain, support email, sender display name, login subtitle, footer/legal text, logo, favicon, PDF letterhead, and primary/secondary colors.</li>
|
||||||
<li>Shared header/logo rendering now uses the branding context processor instead of hardcoded TUBCO asset references.</li>
|
<li>Shared header/logo rendering now uses the branding context processor instead of hardcoded TUBCO asset references.</li>
|
||||||
|
<li>The company domain now drives onboarding/offboarding email autofill and domain validation, so new customer deployments no longer require <code>@tub.co</code> code changes.</li>
|
||||||
|
<li>Outgoing system mail sender names are now branded through the same layer.</li>
|
||||||
<li>User invitation emails and welcome-template fallbacks also use the configured branding defaults.</li>
|
<li>User invitation emails and welcome-template fallbacks also use the configured branding defaults.</li>
|
||||||
</ul>
|
</ul>
|
||||||
|
|
||||||
|
|||||||
@@ -178,7 +178,7 @@
|
|||||||
<li><strong>Form Builder:</strong> manage field visibility/order/options.</li>
|
<li><strong>Form Builder:</strong> manage field visibility/order/options.</li>
|
||||||
<li><strong>Einweisungs-Builder:</strong> manage custom checklist items for the intro PDF and live introduction checklist, including section, visibility, and conditional display logic.</li>
|
<li><strong>Einweisungs-Builder:</strong> manage custom checklist items for the intro PDF and live introduction checklist, including section, visibility, and conditional display logic.</li>
|
||||||
<li><strong>Integrations:</strong> Nextcloud, SMTP, default routing addresses, notification rules, workflow rules, and remote backup target settings.</li>
|
<li><strong>Integrations:</strong> Nextcloud, SMTP, default routing addresses, notification rules, workflow rules, and remote backup target settings.</li>
|
||||||
<li><strong>Branding:</strong> portal title, company name, logo, support email, default language, PDF letterhead, and basic brand colors.</li>
|
<li><strong>Branding:</strong> portal title, company name, company domain, support email, sender display name, logo, favicon, default language, PDF letterhead, footer/legal text, and basic brand colors.</li>
|
||||||
<li><strong>App Registry:</strong> platform-level registry for enabling, ordering, and relabeling landing-page apps without editing the home template.</li>
|
<li><strong>App Registry:</strong> platform-level registry for enabling, ordering, and relabeling landing-page apps without editing the home template.</li>
|
||||||
<li><strong>Benutzer & Rollen:</strong> super-admin-only page for creating users, assigning roles, activating/deactivating access, sending access or password-reset links by email, and deleting accounts when appropriate.</li>
|
<li><strong>Benutzer & Rollen:</strong> super-admin-only page for creating users, assigning roles, activating/deactivating access, sending access or password-reset links by email, and deleting accounts when appropriate.</li>
|
||||||
<li><strong>Welcome Emails:</strong> scheduled jobs, pause/resume/cancel/trigger now.</li>
|
<li><strong>Welcome Emails:</strong> scheduled jobs, pause/resume/cancel/trigger now.</li>
|
||||||
|
|||||||
Reference in New Issue
Block a user