refine form builder workspace interactions
This commit is contained in:
File diff suppressed because it is too large
Load Diff
@@ -10,10 +10,51 @@
|
|||||||
{% block shell_body %}
|
{% block shell_body %}
|
||||||
{% include 'workflows/includes/app_header.html' with header_show_home=1 header_inside_shell=1 %}
|
{% include 'workflows/includes/app_header.html' with header_show_home=1 header_inside_shell=1 %}
|
||||||
|
|
||||||
|
<div class="builder-workspace">
|
||||||
|
<aside class="builder-sidebar">
|
||||||
|
<div class="builder-sidebar-card">
|
||||||
|
<span class="builder-sidebar-eyebrow">{% trans "Arbeitsbereich" %}</span>
|
||||||
|
<h2>{% trans "Formularsteuerung" %}</h2>
|
||||||
|
<p>{% trans "Arbeiten Sie blockweise: zuerst Struktur, dann Regeln, danach Inhalte und Erweiterungen." %}</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<nav class="builder-side-nav" aria-label="{% trans 'Builder Navigation' %}">
|
||||||
|
<a class="builder-side-link{% if active_module == 'structure' %} is-active{% endif %}" href="/admin-tools/form-builder/?form_type={{ form_type }}&option_category={{ selected_option_category }}&module=structure">
|
||||||
|
<span class="builder-side-link-title">{% trans "Struktur & Reihenfolge" %}</span>
|
||||||
|
<span class="builder-side-link-meta">{{ columns|length }} {% trans "Abschnitte" %}</span>
|
||||||
|
</a>
|
||||||
|
<a class="builder-side-link{% if active_module == 'section-rules' or active_module == 'field-rules' or active_module == 'conditional-rules' %} is-active{% endif %}" href="/admin-tools/form-builder/?form_type={{ form_type }}&option_category={{ selected_option_category }}&module=field-rules">
|
||||||
|
<span class="builder-side-link-title">{% trans "Sichtbarkeit & Regeln" %}</span>
|
||||||
|
<span class="builder-side-link-meta">{{ builder_summary.hidden_field_count }} {% trans "ausgeblendet" %}</span>
|
||||||
|
</a>
|
||||||
|
<a class="builder-side-link{% if active_module == 'options' or active_module == 'field-texts' or active_module == 'custom-sections' or active_module == 'custom-fields' or active_module == 'preview' %} is-active{% endif %}" href="/admin-tools/form-builder/?form_type={{ form_type }}&option_category={{ selected_option_category }}&module=options">
|
||||||
|
<span class="builder-side-link-title">{% trans "Optionen & Texte" %}</span>
|
||||||
|
<span class="builder-side-link-meta">{{ builder_summary.custom_field_count }} {% trans "eigene Felder" %}</span>
|
||||||
|
</a>
|
||||||
|
</nav>
|
||||||
|
|
||||||
|
<div class="builder-sidebar-card builder-sidebar-stats">
|
||||||
|
<div class="builder-side-stat">
|
||||||
|
<strong>{{ builder_summary.configurable_field_count }}</strong>
|
||||||
|
<span>{% trans "konfigurierbare Felder" %}</span>
|
||||||
|
</div>
|
||||||
|
<div class="builder-side-stat">
|
||||||
|
<strong>{{ builder_summary.custom_section_count }}</strong>
|
||||||
|
<span>{% trans "eigene Abschnitte" %}</span>
|
||||||
|
</div>
|
||||||
|
<div class="builder-side-stat">
|
||||||
|
<strong>{{ builder_summary.custom_field_count }}</strong>
|
||||||
|
<span>{% trans "eigene Felder" %}</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</aside>
|
||||||
|
|
||||||
|
<main class="builder-main">
|
||||||
<section class="builder-hero">
|
<section class="builder-hero">
|
||||||
<div class="builder-hero-copy">
|
<div class="builder-hero-copy">
|
||||||
<span class="builder-eyebrow">{% trans "Deployment Configuration" %}</span>
|
<span class="builder-eyebrow">{% trans "Deployment Configuration" %}</span>
|
||||||
<h1>{% trans "Form Builder" %}</h1>
|
<h1>{% trans "Form Builder" %}</h1>
|
||||||
|
<p class="builder-hero-sub">{% trans "Steuern Sie Struktur, Regeln und Inhalte Ihrer Standard-Workflows an einem Ort." %}</p>
|
||||||
</div>
|
</div>
|
||||||
<div class="builder-hero-actions">
|
<div class="builder-hero-actions">
|
||||||
{% for key, label in form_types %}
|
{% for key, label in form_types %}
|
||||||
@@ -32,75 +73,150 @@
|
|||||||
|
|
||||||
<div id="status-message" class="status" aria-live="polite"></div>
|
<div id="status-message" class="status" aria-live="polite"></div>
|
||||||
|
|
||||||
<details class="builder-panel builder-accordion js-single-accordion" data-accordion-group="builder-panels" id="builder-structure" {% if active_panel == 'builder-structure' %}open{% endif %}>
|
<section class="builder-panel builder-module-surface{% if active_module != 'structure' %} builder-module-hidden{% endif %}" id="builder-structure">
|
||||||
<summary class="builder-panel-summary">
|
<div class="builder-panel-body builder-panel-body-static">
|
||||||
<div class="builder-panel-head">
|
<div class="builder-panel-head">
|
||||||
<div>
|
<div class="builder-panel-copy">
|
||||||
<h2>{% trans "Struktur & Reihenfolge" %}</h2>
|
<h2>{% trans "Struktur & Reihenfolge" %}</h2>
|
||||||
|
<p class="builder-panel-sub">{% trans "Ordnen Sie Abschnitte und Felder in der Reihenfolge, in der sie im Formular erscheinen sollen." %}</p>
|
||||||
|
</div>
|
||||||
|
<div class="builder-panel-meta">
|
||||||
|
<span class="builder-panel-count">{{ columns|length }} {% trans "Abschnitte" %}</span>
|
||||||
|
<span class="builder-panel-count">{{ builder_summary.configurable_field_count }} {% trans "konfigurierbare Felder" %}</span>
|
||||||
</div>
|
</div>
|
||||||
<span class="builder-panel-toggle">{% trans "Geöffnet" %}</span>
|
|
||||||
</div>
|
</div>
|
||||||
</summary>
|
|
||||||
<div class="builder-panel-body">
|
|
||||||
|
|
||||||
<div class="columns {% if columns|length == 1 %}single{% endif %}" id="builder-columns" data-form-type="{{ form_type }}">
|
<div class="structure-workspace">
|
||||||
{% for column in columns %}
|
<aside class="structure-sidebar">
|
||||||
<section class="column" data-column-key="{{ column.key }}">
|
<section class="structure-card">
|
||||||
<div class="column-head">
|
<span class="structure-card-eyebrow">{% trans "Arbeitsmodus" %}</span>
|
||||||
<h3>{{ column.title }}</h3>
|
<h3>{% trans "Direkte Anordnung" %}</h3>
|
||||||
<span class="column-count">{% blocktrans trimmed with count=column.items|length %}{{ count }} Feld/Felder{% endblocktrans %}</span>
|
<p>{% trans "Verschieben Sie Felder direkt zwischen Abschnitten. Die Reihenfolge wird erst mit dem globalen Speichern oben übernommen." %}</p>
|
||||||
</div>
|
</section>
|
||||||
<div class="dropzone" data-column-key="{{ column.key }}">
|
|
||||||
{% for item in column.items %}
|
|
||||||
<article class="field-card" draggable="true" data-field-name="{{ item.field_name }}">
|
|
||||||
<div class="field-main">
|
|
||||||
<div class="field-label">{{ item.label }}</div>
|
|
||||||
<div class="field-name">{{ item.field_name }}</div>
|
|
||||||
</div>
|
|
||||||
<div class="badges">
|
|
||||||
{% if item.is_custom %}<span class="badge">{% trans "Eigen" %}</span>{% endif %}
|
|
||||||
{% if item.locked %}<span class="badge locked">{% trans "Fix" %}</span>{% endif %}
|
|
||||||
{% if not item.is_visible %}<span class="badge hidden">{% trans "Ausgeblendet" %}</span>{% endif %}
|
|
||||||
{% if item.is_required %}<span class="badge required">{% trans "Pflicht" %}</span>{% endif %}
|
|
||||||
</div>
|
|
||||||
</article>
|
|
||||||
{% endfor %}
|
|
||||||
</div>
|
|
||||||
</section>
|
|
||||||
{% endfor %}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</details>
|
|
||||||
|
|
||||||
<details class="builder-panel builder-accordion js-single-accordion" data-accordion-group="builder-panels" id="builder-rules" {% if active_panel == 'builder-rules' %}open{% endif %}>
|
<section class="structure-card structure-card-muted">
|
||||||
<summary class="builder-panel-summary">
|
<div class="structure-stat">
|
||||||
|
<strong>{{ columns|length }}</strong>
|
||||||
|
<span>{% trans "aktive Abschnitte" %}</span>
|
||||||
|
</div>
|
||||||
|
<div class="structure-stat">
|
||||||
|
<strong>{{ builder_summary.custom_field_count }}</strong>
|
||||||
|
<span>{% trans "eigene Felder" %}</span>
|
||||||
|
</div>
|
||||||
|
<div class="structure-stat">
|
||||||
|
<strong>{{ builder_summary.hidden_field_count }}</strong>
|
||||||
|
<span>{% trans "ausgeblendete Felder" %}</span>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
</aside>
|
||||||
|
|
||||||
|
<div class="structure-canvas">
|
||||||
|
<nav class="structure-section-nav" aria-label="{% trans 'Abschnitte' %}">
|
||||||
|
{% for column in columns %}
|
||||||
|
<a class="structure-section-pill{% if active_structure_section == column.key %} is-active{% endif %}" href="/admin-tools/form-builder/?form_type={{ form_type }}&option_category={{ selected_option_category }}&module=structure&structure_section={{ column.key }}">
|
||||||
|
<span class="structure-section-pill-index">{{ forloop.counter }}</span>
|
||||||
|
<span class="structure-section-pill-copy">
|
||||||
|
<strong>{{ column.title }}</strong>
|
||||||
|
<span>{% blocktrans trimmed with count=column.items|length %}{{ count }} Feld/Felder{% endblocktrans %}</span>
|
||||||
|
</span>
|
||||||
|
</a>
|
||||||
|
{% endfor %}
|
||||||
|
</nav>
|
||||||
|
|
||||||
|
<div class="columns structure-columns-single" id="builder-columns" data-form-type="{{ form_type }}">
|
||||||
|
{% for column in columns %}
|
||||||
|
{% if active_structure_section == column.key %}
|
||||||
|
<section class="column is-active" data-column-key="{{ column.key }}">
|
||||||
|
<div class="column-head">
|
||||||
|
<div>
|
||||||
|
<h3>{{ column.title }}</h3>
|
||||||
|
<span class="column-count">{% blocktrans trimmed with count=column.items|length %}{{ count }} Feld/Felder{% endblocktrans %}</span>
|
||||||
|
</div>
|
||||||
|
<span class="builder-panel-count">{% trans "Geöffnet" %}</span>
|
||||||
|
</div>
|
||||||
|
<div class="dropzone" data-column-key="{{ column.key }}">
|
||||||
|
{% for item in column.items %}
|
||||||
|
<article class="field-card" draggable="true" data-field-name="{{ item.field_name }}">
|
||||||
|
<div class="field-main">
|
||||||
|
<div class="field-label">{{ item.label }}</div>
|
||||||
|
<div class="field-name">{{ item.field_name }}</div>
|
||||||
|
</div>
|
||||||
|
<div class="badges">
|
||||||
|
{% if item.is_custom %}<span class="badge">{% trans "Eigen" %}</span>{% endif %}
|
||||||
|
{% if item.locked %}<span class="badge locked">{% trans "Fix" %}</span>{% endif %}
|
||||||
|
{% if not item.is_visible %}<span class="badge hidden">{% trans "Ausgeblendet" %}</span>{% endif %}
|
||||||
|
{% if item.is_required %}<span class="badge required">{% trans "Pflicht" %}</span>{% endif %}
|
||||||
|
</div>
|
||||||
|
</article>
|
||||||
|
{% empty %}
|
||||||
|
<div class="structure-empty">{% trans "Noch keine Felder in diesem Abschnitt." %}</div>
|
||||||
|
{% endfor %}
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
{% endif %}
|
||||||
|
{% endfor %}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<section class="builder-panel builder-module-surface{% if active_module != 'section-rules' and active_module != 'field-rules' and active_module != 'conditional-rules' %} builder-module-hidden{% endif %}" id="builder-rules">
|
||||||
|
<div class="builder-panel-body builder-panel-body-static">
|
||||||
<div class="builder-panel-head">
|
<div class="builder-panel-head">
|
||||||
<div>
|
<div class="builder-panel-copy">
|
||||||
<h2>{% trans "Sichtbarkeit & Regeln" %}</h2>
|
<h2>{% trans "Sichtbarkeit & Regeln" %}</h2>
|
||||||
|
<p class="builder-panel-sub">{% trans "Legen Sie fest, welche Teile sichtbar, erforderlich oder regelgesteuert sein sollen." %}</p>
|
||||||
|
</div>
|
||||||
|
<div class="builder-panel-meta">
|
||||||
|
<span class="builder-panel-count">{{ builder_summary.hidden_field_count }} {% trans "ausgeblendet" %}</span>
|
||||||
|
<span class="builder-panel-count">{{ builder_summary.hidden_section_count }} {% trans "versteckte Abschnitte" %}</span>
|
||||||
</div>
|
</div>
|
||||||
<span class="builder-panel-toggle">{% trans "Öffnen" %}</span>
|
|
||||||
</div>
|
</div>
|
||||||
</summary>
|
|
||||||
<div class="builder-panel-body">
|
<nav class="builder-module-nav" aria-label="{% trans 'Regelmodule' %}">
|
||||||
|
<a class="builder-module-link{% if active_module == 'section-rules' %} is-active{% endif %}" href="/admin-tools/form-builder/?form_type={{ form_type }}&option_category={{ selected_option_category }}&module=section-rules">{% trans "Abschnitte" %}</a>
|
||||||
|
<a class="builder-module-link{% if active_module == 'field-rules' %} is-active{% endif %}" href="/admin-tools/form-builder/?form_type={{ form_type }}&option_category={{ selected_option_category }}&module=field-rules">{% trans "Feldregeln" %}</a>
|
||||||
|
{% if form_type == 'onboarding' %}
|
||||||
|
<a class="builder-module-link{% if active_module == 'conditional-rules' %} is-active{% endif %}" href="/admin-tools/form-builder/?form_type={{ form_type }}&option_category={{ selected_option_category }}&module=conditional-rules">{% trans "Bedingte Logik" %}</a>
|
||||||
|
{% endif %}
|
||||||
|
</nav>
|
||||||
|
|
||||||
<div class="builder-stack-layout">
|
<div class="builder-stack-layout">
|
||||||
<details class="options-panel nested-accordion js-single-accordion" data-accordion-group="builder-rules-subpanels" {% if active_rules_panel == 'section-rules' %}open{% endif %}>
|
{% if active_module == 'section-rules' %}
|
||||||
<summary class="nested-accordion-summary">
|
<section class="options-panel builder-module-card custom-fields-surface">
|
||||||
|
<div class="module-card-body">
|
||||||
<div class="options-head">
|
<div class="options-head">
|
||||||
<h2>{% trans "Abschnitte steuern" %}</h2>
|
<div class="options-copy">
|
||||||
<span class="builder-panel-toggle">{% trans "Öffnen" %}</span>
|
<h2>{% trans "Abschnitte steuern" %}</h2>
|
||||||
|
<p class="options-sub">{% trans "Reihenfolge und Sichtbarkeit der Formularabschnitte." %}</p>
|
||||||
|
</div>
|
||||||
|
<div class="builder-panel-meta">
|
||||||
|
<span class="builder-panel-count">{{ section_rule_items|length }} {% trans "Abschnitte" %}</span>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</summary>
|
|
||||||
<div class="nested-accordion-body">
|
|
||||||
<form method="post" action="/admin-tools/form-builder/?form_type={{ form_type }}&option_category={{ selected_option_category }}">
|
<form method="post" action="/admin-tools/form-builder/?form_type={{ form_type }}&option_category={{ selected_option_category }}">
|
||||||
{% csrf_token %}
|
{% csrf_token %}
|
||||||
|
<input type="hidden" name="section_rules_section" value="{{ active_section_rules_section }}" />
|
||||||
|
<nav class="structure-section-nav" aria-label="{% trans 'Abschnittsregeln' %}">
|
||||||
|
{% for section in section_rule_items %}
|
||||||
|
<a class="structure-section-pill{% if active_section_rules_section == section.key %} is-active{% endif %}" href="/admin-tools/form-builder/?form_type={{ form_type }}&option_category={{ selected_option_category }}&module=section-rules§ion_rules_section={{ section.key }}">
|
||||||
|
<span class="structure-section-pill-copy">
|
||||||
|
<strong>{{ section.title }}</strong>
|
||||||
|
<span>{% blocktrans trimmed with count=section.field_count %}{{ count }} Feld/Felder{% endblocktrans %}</span>
|
||||||
|
</span>
|
||||||
|
</a>
|
||||||
|
{% endfor %}
|
||||||
|
</nav>
|
||||||
<div class="section-rule-grid" id="section-rule-grid">
|
<div class="section-rule-grid" id="section-rule-grid">
|
||||||
{% for section in section_rule_items %}
|
{% for section in section_rule_items %}
|
||||||
|
{% if active_section_rules_section == section.key %}
|
||||||
<article
|
<article
|
||||||
class="section-rule-card{% if section.locked %} is-locked{% endif %}"
|
class="section-rule-card{% if section.locked %} is-locked{% endif %}"
|
||||||
data-section-key="{{ section.key }}"
|
data-section-key="{{ section.key }}"
|
||||||
>
|
>
|
||||||
<input type="hidden" name="section_order" value="{{ section.key }}" />
|
<input type="hidden" name="section_order" value="{{ section.key }}" />
|
||||||
|
<div class="section-rule-order">{{ forloop.counter }}</div>
|
||||||
<div class="section-rule-actions">
|
<div class="section-rule-actions">
|
||||||
<button class="section-move-btn" type="button" data-move-section="up" aria-label="{% trans 'Nach oben' %}" title="{% trans 'Nach oben' %}">
|
<button class="section-move-btn" type="button" data-move-section="up" aria-label="{% trans 'Nach oben' %}" title="{% trans 'Nach oben' %}">
|
||||||
<span aria-hidden="true">↑</span>
|
<span aria-hidden="true">↑</span>
|
||||||
@@ -129,27 +245,44 @@
|
|||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
</article>
|
</article>
|
||||||
|
{% endif %}
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</div>
|
</div>
|
||||||
<div class="options-actions">
|
<div class="options-actions options-actions-sticky">
|
||||||
<button class="btn btn-primary" type="submit" name="builder_action" value="save_section_rules">{% trans "Abschnittsregeln speichern" %}</button>
|
<button class="btn btn-primary" type="submit" name="builder_action" value="save_section_rules">{% trans "Abschnittsregeln speichern" %}</button>
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
</details>
|
</section>
|
||||||
|
{% elif active_module == 'field-rules' %}
|
||||||
|
|
||||||
<details class="options-panel nested-accordion js-single-accordion" data-accordion-group="builder-rules-subpanels" {% if active_rules_panel == 'field-rules' %}open{% endif %}>
|
<section class="options-panel builder-module-card">
|
||||||
<summary class="nested-accordion-summary">
|
<div class="module-card-body">
|
||||||
<div class="options-head">
|
<div class="options-head">
|
||||||
<h2>{% trans "Feldregeln verwalten" %}</h2>
|
<div class="options-copy">
|
||||||
<span class="builder-panel-toggle">{% trans "Öffnen" %}</span>
|
<h2>{% trans "Feldregeln verwalten" %}</h2>
|
||||||
|
<p class="options-sub">{% trans "Steuern Sie Sichtbarkeit und Pflichtstatus für einzelne Felder." %}</p>
|
||||||
|
</div>
|
||||||
|
<div class="builder-panel-meta">
|
||||||
|
<span class="builder-panel-count">{{ builder_summary.configurable_field_count }} {% trans "konfigurierbar" %}</span>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</summary>
|
|
||||||
<div class="nested-accordion-body">
|
|
||||||
<form method="post" action="/admin-tools/form-builder/?form_type={{ form_type }}&option_category={{ selected_option_category }}">
|
<form method="post" action="/admin-tools/form-builder/?form_type={{ form_type }}&option_category={{ selected_option_category }}">
|
||||||
{% csrf_token %}
|
{% csrf_token %}
|
||||||
|
<input type="hidden" name="field_rules_section" value="{{ active_field_rules_section }}" />
|
||||||
|
<nav class="structure-section-nav" aria-label="{% trans 'Feldregel-Abschnitte' %}">
|
||||||
|
{% for group in field_rule_groups %}
|
||||||
|
<a class="structure-section-pill{% if active_field_rules_section == group.key %} is-active{% endif %}" href="/admin-tools/form-builder/?form_type={{ form_type }}&option_category={{ selected_option_category }}&module=field-rules&field_rules_section={{ group.key }}">
|
||||||
|
<span class="structure-section-pill-copy">
|
||||||
|
<strong>{{ group.title }}</strong>
|
||||||
|
<span>{% blocktrans trimmed with count=group.items|length %}{{ count }} Feld/Felder{% endblocktrans %}</span>
|
||||||
|
</span>
|
||||||
|
</a>
|
||||||
|
{% endfor %}
|
||||||
|
</nav>
|
||||||
<div class="field-rule-groups">
|
<div class="field-rule-groups">
|
||||||
{% for group in field_rule_groups %}
|
{% for group in field_rule_groups %}
|
||||||
|
{% if active_field_rules_section == group.key %}
|
||||||
<section class="field-rule-group">
|
<section class="field-rule-group">
|
||||||
<div class="field-rule-group-head">
|
<div class="field-rule-group-head">
|
||||||
<h3>{{ group.title }}</h3>
|
<h3>{{ group.title }}</h3>
|
||||||
@@ -161,30 +294,34 @@
|
|||||||
<div class="field-rule-main">
|
<div class="field-rule-main">
|
||||||
<input type="hidden" name="field_rule_ids" value="{{ item.id }}" />
|
<input type="hidden" name="field_rule_ids" value="{{ item.id }}" />
|
||||||
<strong>{{ item.label }}</strong>
|
<strong>{{ item.label }}</strong>
|
||||||
<div class="mini">{{ item.field_name }}</div>
|
<div class="field-rule-meta">
|
||||||
|
<span class="entity-meta">{{ item.field_name }}</span>
|
||||||
|
<div class="field-rule-status field-rule-status-inline">
|
||||||
|
{% if item.locked %}
|
||||||
|
<span class="badge locked">{% trans "Fix" %}</span>
|
||||||
|
{% elif not item.is_visible %}
|
||||||
|
<span class="badge hidden">{% trans "Ausgeblendet" %}</span>
|
||||||
|
{% elif item.is_required %}
|
||||||
|
<span class="badge required">{% trans "Pflicht" %}</span>
|
||||||
|
{% else %}
|
||||||
|
<span class="badge">{% trans "Flexibel" %}</span>
|
||||||
|
{% endif %}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<label class="field-rule-control">
|
<div class="field-rule-settings">
|
||||||
<span>{% trans "Sichtbar" %}</span>
|
<label class="field-rule-control field-rule-control-compact">
|
||||||
<input type="checkbox" name="is_visible_{{ item.id }}" {% if item.is_visible %}checked{% endif %} {% if item.locked %}disabled{% endif %}/>
|
<span>{% trans "Sichtbar" %}</span>
|
||||||
</label>
|
<input type="checkbox" name="is_visible_{{ item.id }}" {% if item.is_visible %}checked{% endif %} {% if item.locked %}disabled{% endif %}/>
|
||||||
<label class="field-rule-control">
|
</label>
|
||||||
<span>{% trans "Pflicht" %}</span>
|
<label class="field-rule-control field-rule-control-compact">
|
||||||
<select name="is_required_{{ item.id }}" {% if item.locked %}disabled{% endif %}>
|
<span>{% trans "Pflicht" %}</span>
|
||||||
<option value="" {% if item.is_required is None %}selected{% endif %}>{% trans "Standard" %}</option>
|
<select name="is_required_{{ item.id }}" {% if item.locked %}disabled{% endif %}>
|
||||||
<option value="required" {% if item.is_required is True %}selected{% endif %}>{% trans "Pflicht" %}</option>
|
<option value="" {% if item.is_required is None %}selected{% endif %}>{% trans "Standard" %}</option>
|
||||||
<option value="optional" {% if item.is_required is False %}selected{% endif %}>{% trans "Optional" %}</option>
|
<option value="required" {% if item.is_required is True %}selected{% endif %}>{% trans "Pflicht" %}</option>
|
||||||
</select>
|
<option value="optional" {% if item.is_required is False %}selected{% endif %}>{% trans "Optional" %}</option>
|
||||||
</label>
|
</select>
|
||||||
<div class="field-rule-status">
|
</label>
|
||||||
{% if item.locked %}
|
|
||||||
<span class="badge locked">{% trans "Fix" %}</span>
|
|
||||||
{% elif not item.is_visible %}
|
|
||||||
<span class="badge hidden">{% trans "Ausgeblendet" %}</span>
|
|
||||||
{% elif item.is_required %}
|
|
||||||
<span class="badge required">{% trans "Pflicht" %}</span>
|
|
||||||
{% else %}
|
|
||||||
<span class="badge">{% trans "Flexibel" %}</span>
|
|
||||||
{% endif %}
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{% empty %}
|
{% empty %}
|
||||||
@@ -192,28 +329,44 @@
|
|||||||
{% endfor %}
|
{% endfor %}
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
|
{% endif %}
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</div>
|
</div>
|
||||||
<div class="options-actions">
|
<div class="options-actions options-actions-sticky">
|
||||||
<button class="btn btn-primary" type="submit" name="builder_action" value="save_field_rules">{% trans "Feldregeln speichern" %}</button>
|
<button class="btn btn-primary" type="submit" name="builder_action" value="save_field_rules">{% trans "Feldregeln speichern" %}</button>
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
</details>
|
</section>
|
||||||
|
{% elif form_type == 'onboarding' and active_module == 'conditional-rules' %}
|
||||||
|
|
||||||
{% if form_type == 'onboarding' %}
|
<section class="options-panel builder-module-card">
|
||||||
<details class="options-panel nested-accordion js-single-accordion" data-accordion-group="builder-rules-subpanels" {% if active_rules_panel == 'conditional-rules' %}open{% endif %}>
|
<div class="module-card-body">
|
||||||
<summary class="nested-accordion-summary">
|
|
||||||
<div class="options-head">
|
<div class="options-head">
|
||||||
<h2>{% trans "Bedingte Logik" %}</h2>
|
<div class="options-copy">
|
||||||
<span class="builder-panel-toggle">{% trans "Öffnen" %}</span>
|
<h2>{% trans "Bedingte Logik" %}</h2>
|
||||||
|
<p class="options-sub">{% trans "Lassen Sie Felder abhängig von anderen Antworten ein- oder ausblenden." %}</p>
|
||||||
|
</div>
|
||||||
|
<div class="builder-panel-meta">
|
||||||
|
<span class="builder-panel-count">{{ conditional_rule_items|length }} {% trans "Regeln" %}</span>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</summary>
|
|
||||||
<div class="nested-accordion-body">
|
|
||||||
<form method="post" action="/admin-tools/form-builder/?form_type={{ form_type }}&option_category={{ selected_option_category }}">
|
<form method="post" action="/admin-tools/form-builder/?form_type={{ form_type }}&option_category={{ selected_option_category }}">
|
||||||
{% csrf_token %}
|
{% csrf_token %}
|
||||||
|
<input type="hidden" name="conditional_target" value="{{ active_conditional_target }}" />
|
||||||
|
<nav class="structure-section-nav" aria-label="{% trans 'Bedingte Regeln' %}">
|
||||||
|
{% for item in conditional_rule_items %}
|
||||||
|
<a class="structure-section-pill{% if active_conditional_target == item.target_key %} is-active{% endif %}" href="/admin-tools/form-builder/?form_type={{ form_type }}&option_category={{ selected_option_category }}&module=conditional-rules&conditional_target={{ item.target_key }}">
|
||||||
|
<span class="structure-section-pill-copy">
|
||||||
|
<strong>{{ item.title }}</strong>
|
||||||
|
<span>{% blocktrans trimmed with count=item.target_fields|length %}{{ count }} Ziel-Feld/Felder{% endblocktrans %}</span>
|
||||||
|
</span>
|
||||||
|
</a>
|
||||||
|
{% endfor %}
|
||||||
|
</nav>
|
||||||
<div class="conditional-rule-grid">
|
<div class="conditional-rule-grid">
|
||||||
{% for item in conditional_rule_items %}
|
{% for item in conditional_rule_items %}
|
||||||
|
{% if active_conditional_target == item.target_key %}
|
||||||
<section class="conditional-rule-card">
|
<section class="conditional-rule-card">
|
||||||
<div class="conditional-rule-head">
|
<div class="conditional-rule-head">
|
||||||
<div class="conditional-rule-head-main">
|
<div class="conditional-rule-head-main">
|
||||||
@@ -228,6 +381,26 @@
|
|||||||
<input type="checkbox" name="conditional_active_{{ item.target_key }}" {% if item.is_active %}checked{% endif %} />
|
<input type="checkbox" name="conditional_active_{{ item.target_key }}" {% if item.is_active %}checked{% endif %} />
|
||||||
</label>
|
</label>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="conditional-rule-summary">
|
||||||
|
<span class="conditional-summary-prefix">{% trans "Sichtbar, wenn" %}</span>
|
||||||
|
<div class="conditional-summary-chips">
|
||||||
|
{% with first_clause=item.clauses.0 second_clause=item.clauses.1 %}
|
||||||
|
{% if first_clause.field %}
|
||||||
|
<span class="preview-chip">{{ first_clause.field }}</span>
|
||||||
|
<span class="preview-chip">{{ first_clause.operator }}</span>
|
||||||
|
{% if first_clause.value %}<span class="preview-chip">{{ first_clause.value }}</span>{% endif %}
|
||||||
|
{% else %}
|
||||||
|
<span class="preview-chip">{% trans "Keine Bedingung" %}</span>
|
||||||
|
{% endif %}
|
||||||
|
{% if second_clause.field %}
|
||||||
|
<span class="preview-chip">{% trans "und" %}</span>
|
||||||
|
<span class="preview-chip">{{ second_clause.field }}</span>
|
||||||
|
<span class="preview-chip">{{ second_clause.operator }}</span>
|
||||||
|
{% if second_clause.value %}<span class="preview-chip">{{ second_clause.value }}</span>{% endif %}
|
||||||
|
{% endif %}
|
||||||
|
{% endwith %}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
<div class="conditional-targets">
|
<div class="conditional-targets">
|
||||||
<span class="conditional-target-label">{% trans "Steuert" %}</span>
|
<span class="conditional-target-label">{% trans "Steuert" %}</span>
|
||||||
<div class="conditional-target-chips">
|
<div class="conditional-target-chips">
|
||||||
@@ -238,105 +411,94 @@
|
|||||||
{% endfor %}
|
{% endfor %}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="conditional-clause-list">
|
<div class="conditional-sentence-builder">
|
||||||
{% with first_clause=item.clauses.0 second_clause=item.clauses.1 %}
|
{% with first_clause=item.clauses.0 second_clause=item.clauses.1 %}
|
||||||
<div class="conditional-clause-row">
|
<div class="conditional-sentence-row">
|
||||||
<div class="conditional-clause-index">
|
<span class="conditional-sentence-label">{% trans "Zeige dieses Element, wenn" %}</span>
|
||||||
{% trans "Wenn" %}
|
<select name="conditional_field_{{ item.target_key }}_0">
|
||||||
</div>
|
<option value="">{% trans "Keine" %}</option>
|
||||||
<label class="conditional-clause-control conditional-clause-field">
|
{% for value, label in item.field_choices %}
|
||||||
<span>{% trans "Feld" %}</span>
|
<option value="{{ value }}" {% if first_clause.field == value %}selected{% endif %}>{{ label }}</option>
|
||||||
<select name="conditional_field_{{ item.target_key }}_0">
|
{% endfor %}
|
||||||
<option value="">{% trans "Keine" %}</option>
|
</select>
|
||||||
{% for value, label in item.field_choices %}
|
<select name="conditional_operator_{{ item.target_key }}_0">
|
||||||
<option value="{{ value }}" {% if first_clause.field == value %}selected{% endif %}>{{ label }}</option>
|
{% for value, label in item.operator_choices %}
|
||||||
{% endfor %}
|
<option value="{{ value }}" {% if first_clause.operator == value %}selected{% endif %}>{{ label }}</option>
|
||||||
</select>
|
{% endfor %}
|
||||||
</label>
|
</select>
|
||||||
<label class="conditional-clause-control conditional-clause-operator">
|
<input type="text" name="conditional_value_{{ item.target_key }}_0" value="{{ first_clause.value }}" placeholder="{% trans 'Wert' %}" />
|
||||||
<span>{% trans "Operator" %}</span>
|
|
||||||
<select name="conditional_operator_{{ item.target_key }}_0">
|
|
||||||
{% for value, label in item.operator_choices %}
|
|
||||||
<option value="{{ value }}" {% if first_clause.operator == value %}selected{% endif %}>{{ label }}</option>
|
|
||||||
{% endfor %}
|
|
||||||
</select>
|
|
||||||
</label>
|
|
||||||
<label class="conditional-clause-control conditional-clause-value">
|
|
||||||
<span>{% trans "Wert" %}</span>
|
|
||||||
<input type="text" name="conditional_value_{{ item.target_key }}_0" value="{{ first_clause.value }}" {% if first_clause.operator == 'checked' %}placeholder="{% trans 'wird ignoriert' %}"{% endif %} />
|
|
||||||
</label>
|
|
||||||
</div>
|
</div>
|
||||||
<details class="conditional-extra-clause" {% if second_clause.field %}open{% endif %}>
|
<details class="conditional-extra-clause" {% if second_clause.field %}open{% endif %}>
|
||||||
<summary>{% trans "Zusätzliche Bedingung" %}</summary>
|
<summary>{% trans "Zusätzliche Bedingung" %}</summary>
|
||||||
<div class="conditional-clause-row conditional-clause-row-secondary">
|
<div class="conditional-sentence-row conditional-sentence-row-secondary">
|
||||||
<div class="conditional-clause-index">
|
<span class="conditional-sentence-label">{% trans "Und zusätzlich" %}</span>
|
||||||
{% trans "Und" %}
|
<select name="conditional_field_{{ item.target_key }}_1">
|
||||||
</div>
|
<option value="">{% trans "Keine" %}</option>
|
||||||
<label class="conditional-clause-control conditional-clause-field">
|
{% for value, label in item.field_choices %}
|
||||||
<span>{% trans "Feld" %}</span>
|
<option value="{{ value }}" {% if second_clause.field == value %}selected{% endif %}>{{ label }}</option>
|
||||||
<select name="conditional_field_{{ item.target_key }}_1">
|
{% endfor %}
|
||||||
<option value="">{% trans "Keine" %}</option>
|
</select>
|
||||||
{% for value, label in item.field_choices %}
|
<select name="conditional_operator_{{ item.target_key }}_1">
|
||||||
<option value="{{ value }}" {% if second_clause.field == value %}selected{% endif %}>{{ label }}</option>
|
{% for value, label in item.operator_choices %}
|
||||||
{% endfor %}
|
<option value="{{ value }}" {% if second_clause.operator == value %}selected{% endif %}>{{ label }}</option>
|
||||||
</select>
|
{% endfor %}
|
||||||
</label>
|
</select>
|
||||||
<label class="conditional-clause-control conditional-clause-operator">
|
<input type="text" name="conditional_value_{{ item.target_key }}_1" value="{{ second_clause.value }}" placeholder="{% trans 'Wert' %}" />
|
||||||
<span>{% trans "Operator" %}</span>
|
|
||||||
<select name="conditional_operator_{{ item.target_key }}_1">
|
|
||||||
{% for value, label in item.operator_choices %}
|
|
||||||
<option value="{{ value }}" {% if second_clause.operator == value %}selected{% endif %}>{{ label }}</option>
|
|
||||||
{% endfor %}
|
|
||||||
</select>
|
|
||||||
</label>
|
|
||||||
<label class="conditional-clause-control conditional-clause-value">
|
|
||||||
<span>{% trans "Wert" %}</span>
|
|
||||||
<input type="text" name="conditional_value_{{ item.target_key }}_1" value="{{ second_clause.value }}" {% if second_clause.operator == 'checked' %}placeholder="{% trans 'wird ignoriert' %}"{% endif %} />
|
|
||||||
</label>
|
|
||||||
</div>
|
</div>
|
||||||
</details>
|
</details>
|
||||||
{% endwith %}
|
{% endwith %}
|
||||||
</div>
|
</div>
|
||||||
|
<div class="conditional-clause-list">
|
||||||
|
<span class="mini">{% trans "Nutzen Sie die zusätzliche Bedingung nur, wenn ein zweites Kriterium wirklich nötig ist." %}</span>
|
||||||
|
</div>
|
||||||
</section>
|
</section>
|
||||||
|
{% endif %}
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</div>
|
</div>
|
||||||
<div class="options-actions">
|
<div class="options-actions options-actions-sticky">
|
||||||
<button class="btn btn-primary" type="submit" name="builder_action" value="save_conditional_rules">{% trans "Bedingte Logik speichern" %}</button>
|
<button class="btn btn-primary" type="submit" name="builder_action" value="save_conditional_rules">{% trans "Bedingte Logik speichern" %}</button>
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
</details>
|
</section>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</details>
|
</section>
|
||||||
|
|
||||||
<details class="builder-panel builder-accordion js-single-accordion" data-accordion-group="builder-panels" id="builder-content" {% if active_panel == 'builder-content' %}open{% endif %}>
|
<section class="builder-panel builder-module-surface{% if active_module != 'options' and active_module != 'field-texts' and active_module != 'custom-sections' and active_module != 'custom-fields' and active_module != 'preview' %} builder-module-hidden{% endif %}" id="builder-content">
|
||||||
<summary class="builder-panel-summary">
|
<div class="builder-panel-body builder-panel-body-static">
|
||||||
<div class="builder-panel-head">
|
<div class="builder-panel-head">
|
||||||
<div>
|
<div class="builder-panel-copy">
|
||||||
<h2>{% trans "Optionen & Texte" %}</h2>
|
<h2>{% trans "Optionen & Texte" %}</h2>
|
||||||
|
<p class="builder-panel-sub">{% trans "Pflegen Sie Auswahlwerte, Feldtexte und benutzerdefinierte Erweiterungen." %}</p>
|
||||||
|
</div>
|
||||||
|
<div class="builder-panel-meta">
|
||||||
|
<span class="builder-panel-count">{{ builder_summary.custom_field_count }} {% trans "eigene Felder" %}</span>
|
||||||
|
{% if form_type == 'onboarding' %}
|
||||||
|
<span class="builder-panel-count">{{ builder_summary.custom_section_count }} {% trans "eigene Abschnitte" %}</span>
|
||||||
|
{% endif %}
|
||||||
</div>
|
</div>
|
||||||
<span class="builder-panel-toggle">{% trans "Öffnen" %}</span>
|
|
||||||
</div>
|
</div>
|
||||||
</summary>
|
|
||||||
<div class="builder-panel-body">
|
<nav class="builder-module-nav" aria-label="{% trans 'Inhaltsmodule' %}">
|
||||||
|
<a class="builder-module-link{% if active_module == 'options' %} is-active{% endif %}" href="/admin-tools/form-builder/?form_type={{ form_type }}&option_category={{ selected_option_category }}&module=options">{% trans "Optionen" %}</a>
|
||||||
|
<a class="builder-module-link{% if active_module == 'field-texts' %} is-active{% endif %}" href="/admin-tools/form-builder/?form_type={{ form_type }}&option_category={{ selected_option_category }}&module=field-texts">{% trans "Feldtexte" %}</a>
|
||||||
|
{% if form_type == 'onboarding' %}
|
||||||
|
<a class="builder-module-link{% if active_module == 'custom-sections' %} is-active{% endif %}" href="/admin-tools/form-builder/?form_type={{ form_type }}&option_category={{ selected_option_category }}&module=custom-sections">{% trans "Eigene Abschnitte" %}</a>
|
||||||
|
{% endif %}
|
||||||
|
<a class="builder-module-link{% if active_module == 'custom-fields' %} is-active{% endif %}" href="/admin-tools/form-builder/?form_type={{ form_type }}&option_category={{ selected_option_category }}&module=custom-fields">{% trans "Eigene Felder" %}</a>
|
||||||
|
<a class="builder-module-link{% if active_module == 'preview' %} is-active{% endif %}" href="/admin-tools/form-builder/?form_type={{ form_type }}&option_category={{ selected_option_category }}&module=preview">{% trans "Vorschau" %}</a>
|
||||||
|
</nav>
|
||||||
|
|
||||||
<div class="builder-stack-layout">
|
<div class="builder-stack-layout">
|
||||||
<details class="options-panel nested-accordion js-single-accordion" data-accordion-group="builder-content-subpanels" {% if active_subpanel == 'options' %}open{% endif %}>
|
{% if active_module == 'options' %}
|
||||||
<summary class="nested-accordion-summary">
|
<section class="options-panel builder-module-card">
|
||||||
<div class="options-head">
|
<div class="module-card-body">
|
||||||
<h2>{% trans "Optionen verwalten" %}</h2>
|
|
||||||
<span class="builder-panel-toggle">{% trans "Öffnen" %}</span>
|
|
||||||
</div>
|
|
||||||
</summary>
|
|
||||||
<div class="nested-accordion-body">
|
|
||||||
<div class="options-head options-head-inline">
|
<div class="options-head options-head-inline">
|
||||||
<form class="category-switch" method="get" action="/admin-tools/form-builder/">
|
<form class="category-switch" method="get" action="/admin-tools/form-builder/">
|
||||||
<input type="hidden" name="form_type" value="{{ form_type }}" />
|
<input type="hidden" name="form_type" value="{{ form_type }}" />
|
||||||
<input type="hidden" name="anchor" value="builder-content" />
|
<input type="hidden" name="module" value="options" />
|
||||||
<input type="hidden" name="panel" value="builder-content" />
|
|
||||||
<input type="hidden" name="subpanel" value="options" />
|
|
||||||
<label for="option_category">{% trans "Kategorie" %}</label>
|
<label for="option_category">{% trans "Kategorie" %}</label>
|
||||||
<select id="option_category" name="option_category" onchange="this.form.submit()">
|
<select id="option_category" name="option_category" onchange="this.form.submit()">
|
||||||
{% for value, label in option_categories %}
|
{% for value, label in option_categories %}
|
||||||
@@ -358,106 +520,130 @@
|
|||||||
|
|
||||||
<form method="post" action="/admin-tools/form-builder/?form_type={{ form_type }}&option_category={{ selected_option_category }}">
|
<form method="post" action="/admin-tools/form-builder/?form_type={{ form_type }}&option_category={{ selected_option_category }}">
|
||||||
{% csrf_token %}
|
{% csrf_token %}
|
||||||
<div class="option-table-wrap">
|
<div class="option-card-list" id="option-table-body">
|
||||||
<table class="option-table">
|
{% for item in option_items %}
|
||||||
<thead>
|
<article class="option-row option-card" draggable="true" data-option-row="1">
|
||||||
<tr>
|
<input type="hidden" name="option_ids" value="{{ item.id }}" />
|
||||||
<th>{% trans "Sortierung" %}</th>
|
<div class="option-card-head">
|
||||||
<th>{% trans "Label (DE)" %}</th>
|
<div class="option-card-order">
|
||||||
<th>{% trans "Label (EN)" %}</th>
|
<span class="drag-handle" title="{% trans 'Ziehen zum Sortieren' %}">⋮⋮</span>
|
||||||
<th>Value</th>
|
<div class="option-card-title-block">
|
||||||
<th>{% trans "Aktiv" %}</th>
|
<strong>{{ item.label }}</strong>
|
||||||
<th>{% trans "Löschen" %}</th>
|
<span class="option-card-meta">#{{ forloop.counter }}{% if item.value %} · {{ item.value }}{% endif %}</span>
|
||||||
</tr>
|
</div>
|
||||||
</thead>
|
</div>
|
||||||
<tbody id="option-table-body">
|
<div class="option-card-actions">
|
||||||
{% for item in option_items %}
|
<label class="option-card-toggle">
|
||||||
<tr class="option-row" draggable="true" data-option-row="1">
|
<input type="checkbox" name="active_{{ item.id }}" {% if item.is_active %}checked{% endif %} />
|
||||||
<td>
|
<span>{% trans "Aktiv" %}</span>
|
||||||
<input type="hidden" name="option_ids" value="{{ item.id }}" />
|
</label>
|
||||||
<span class="drag-handle" title="{% trans 'Ziehen zum Sortieren' %}">⋮⋮</span>
|
<button class="btn btn-secondary" type="submit" name="delete_option_id" value="{{ item.id }}" data-confirm="{% trans 'Option wirklich löschen?' %}">{% trans "Löschen" %}</button>
|
||||||
</td>
|
</div>
|
||||||
<td><input type="text" name="label_{{ item.id }}" value="{{ item.label }}" required /></td>
|
</div>
|
||||||
<td><input type="text" name="label_en_{{ item.id }}" value="{{ item.label_en }}" /></td>
|
<div class="option-card-grid">
|
||||||
<td><input type="text" name="value_{{ item.id }}" value="{{ item.value }}" /></td>
|
<label class="builder-entity-control">
|
||||||
<td><input type="checkbox" name="active_{{ item.id }}" {% if item.is_active %}checked{% endif %} /></td>
|
<span>{% trans "Label (DE)" %}</span>
|
||||||
<td>
|
<input type="text" name="label_{{ item.id }}" value="{{ item.label }}" required />
|
||||||
<button class="btn btn-secondary" type="submit" name="delete_option_id" value="{{ item.id }}" data-confirm="{% trans 'Option wirklich löschen?' %}">{% trans "Löschen" %}</button>
|
</label>
|
||||||
</td>
|
<label class="builder-entity-control">
|
||||||
</tr>
|
<span>{% trans "Label (EN)" %}</span>
|
||||||
{% empty %}
|
<input type="text" name="label_en_{{ item.id }}" value="{{ item.label_en }}" />
|
||||||
<tr><td colspan="6">{% trans "Keine Optionen in dieser Kategorie." %}</td></tr>
|
</label>
|
||||||
{% endfor %}
|
<label class="builder-entity-control">
|
||||||
</tbody>
|
<span>Value</span>
|
||||||
</table>
|
<input type="text" name="value_{{ item.id }}" value="{{ item.value }}" />
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
</article>
|
||||||
|
{% empty %}
|
||||||
|
<div class="option-empty-state">{% trans "Keine Optionen in dieser Kategorie." %}</div>
|
||||||
|
{% endfor %}
|
||||||
</div>
|
</div>
|
||||||
<div class="options-actions">
|
<div class="options-actions options-actions-sticky">
|
||||||
<button class="btn btn-primary" type="submit" name="builder_action" value="save_options">{% trans "Optionen speichern" %}</button>
|
<button class="btn btn-primary" type="submit" name="builder_action" value="save_options">{% trans "Optionen speichern" %}</button>
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
</details>
|
</section>
|
||||||
|
{% elif active_module == 'field-texts' %}
|
||||||
|
|
||||||
<details class="options-panel nested-accordion js-single-accordion" data-accordion-group="builder-content-subpanels" {% if active_subpanel == 'field-texts' %}open{% endif %}>
|
<section class="options-panel builder-module-card">
|
||||||
<summary class="nested-accordion-summary">
|
<div class="module-card-body">
|
||||||
<div class="options-head">
|
<div class="options-head">
|
||||||
<h2>{% trans "Feldtexte verwalten" %}</h2>
|
<div class="options-copy">
|
||||||
<span class="builder-panel-toggle">{% trans "Öffnen" %}</span>
|
<h2>{% trans "Feldtexte verwalten" %}</h2>
|
||||||
|
<p class="options-sub">{% trans "Überschreiben Sie Labels und Hilfetexte pro Feld." %}</p>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</summary>
|
|
||||||
<div class="nested-accordion-body">
|
|
||||||
<form method="post" action="/admin-tools/form-builder/?form_type={{ form_type }}&option_category={{ selected_option_category }}">
|
<form method="post" action="/admin-tools/form-builder/?form_type={{ form_type }}&option_category={{ selected_option_category }}">
|
||||||
{% csrf_token %}
|
{% csrf_token %}
|
||||||
<div class="option-table-wrap">
|
<input type="hidden" name="field_texts_section" value="{{ active_field_texts_section }}" />
|
||||||
<table class="option-table">
|
<nav class="structure-section-nav" aria-label="{% trans 'Feldtext-Abschnitte' %}">
|
||||||
<thead>
|
{% for group in field_text_groups %}
|
||||||
<tr>
|
<a class="structure-section-pill{% if active_field_texts_section == group.key %} is-active{% endif %}" href="/admin-tools/form-builder/?form_type={{ form_type }}&option_category={{ selected_option_category }}&module=field-texts&field_texts_section={{ group.key }}">
|
||||||
<th>{% trans "Feld" %}</th>
|
<span class="structure-section-pill-copy">
|
||||||
<th>{% trans "Label (DE)" %}</th>
|
<strong>{{ group.title }}</strong>
|
||||||
<th>{% trans "Label (EN)" %}</th>
|
<span>{% blocktrans trimmed with count=group.items|length %}{{ count }} Feld/Felder{% endblocktrans %}</span>
|
||||||
<th>{% trans "Hilfetext (DE)" %}</th>
|
</span>
|
||||||
<th>{% trans "Hilfetext (EN)" %}</th>
|
</a>
|
||||||
</tr>
|
{% endfor %}
|
||||||
</thead>
|
</nav>
|
||||||
<tbody>
|
<div class="field-text-card-list">
|
||||||
{% for group in field_text_groups %}
|
{% for group in field_text_groups %}
|
||||||
<tr class="option-table-group-row">
|
{% if active_field_texts_section == group.key %}
|
||||||
<th colspan="5">{{ group.title }}</th>
|
{% for item in group.items %}
|
||||||
</tr>
|
<article class="field-text-card">
|
||||||
{% for item in group.items %}
|
<input type="hidden" name="field_ids" value="{{ item.id }}" />
|
||||||
<tr>
|
<div class="field-text-card-head">
|
||||||
<td>
|
<div>
|
||||||
<input type="hidden" name="field_ids" value="{{ item.id }}" />
|
<strong>{{ item.label_override|default:item.field_name }}</strong>
|
||||||
<strong>{{ item.field_name }}</strong>
|
<div class="entity-meta">{{ item.field_name }}</div>
|
||||||
</td>
|
</div>
|
||||||
<td><input type="text" name="label_override_{{ item.id }}" value="{{ item.label_override }}" placeholder="{% trans 'Fallback: Standardlabel' %}" /></td>
|
</div>
|
||||||
<td><input type="text" name="label_override_en_{{ item.id }}" value="{{ item.label_override_en }}" placeholder="{% trans 'English label' %}" /></td>
|
<div class="field-text-card-grid">
|
||||||
<td><input type="text" name="help_text_override_{{ item.id }}" value="{{ item.help_text_override }}" placeholder="{% trans 'Optionaler Hilfetext' %}" /></td>
|
<label class="builder-entity-control">
|
||||||
<td><input type="text" name="help_text_override_en_{{ item.id }}" value="{{ item.help_text_override_en }}" placeholder="{% trans 'Optional English help text' %}" /></td>
|
<span>{% trans "Label (DE)" %}</span>
|
||||||
</tr>
|
<input type="text" name="label_override_{{ item.id }}" value="{{ item.label_override }}" placeholder="{% trans 'Fallback: Standardlabel' %}" />
|
||||||
{% empty %}
|
</label>
|
||||||
<tr><td colspan="5">{% trans "Keine Feldkonfigurationen verfügbar." %}</td></tr>
|
<label class="builder-entity-control">
|
||||||
{% endfor %}
|
<span>{% trans "Label (EN)" %}</span>
|
||||||
{% endfor %}
|
<input type="text" name="label_override_en_{{ item.id }}" value="{{ item.label_override_en }}" placeholder="{% trans 'English label' %}" />
|
||||||
</tbody>
|
</label>
|
||||||
</table>
|
<label class="builder-entity-control">
|
||||||
|
<span>{% trans "Hilfetext (DE)" %}</span>
|
||||||
|
<input type="text" name="help_text_override_{{ item.id }}" value="{{ item.help_text_override }}" placeholder="{% trans 'Optionaler Hilfetext' %}" />
|
||||||
|
</label>
|
||||||
|
<label class="builder-entity-control">
|
||||||
|
<span>{% trans "Hilfetext (EN)" %}</span>
|
||||||
|
<input type="text" name="help_text_override_en_{{ item.id }}" value="{{ item.help_text_override_en }}" placeholder="{% trans 'Optional English help text' %}" />
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
</article>
|
||||||
|
{% empty %}
|
||||||
|
<div class="builder-empty-state">{% trans "Keine Feldkonfigurationen verfügbar." %}</div>
|
||||||
|
{% endfor %}
|
||||||
|
{% endif %}
|
||||||
|
{% endfor %}
|
||||||
</div>
|
</div>
|
||||||
<div class="options-actions">
|
<div class="options-actions options-actions-sticky">
|
||||||
<button class="btn btn-primary" type="submit" name="builder_action" value="save_field_texts">{% trans "Feldtexte speichern" %}</button>
|
<button class="btn btn-primary" type="submit" name="builder_action" value="save_field_texts">{% trans "Feldtexte speichern" %}</button>
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
</details>
|
</section>
|
||||||
|
{% elif form_type == 'onboarding' and active_module == 'custom-sections' %}
|
||||||
|
|
||||||
{% if form_type == 'onboarding' %}
|
<section class="options-panel builder-module-card">
|
||||||
<details class="options-panel nested-accordion js-single-accordion" data-accordion-group="builder-content-subpanels" {% if active_subpanel == 'custom-sections' %}open{% endif %}>
|
<div class="module-card-body">
|
||||||
<summary class="nested-accordion-summary">
|
|
||||||
<div class="options-head">
|
<div class="options-head">
|
||||||
<h2>{% trans "Eigene Abschnitte" %}</h2>
|
<div class="options-copy">
|
||||||
<span class="builder-panel-toggle">{% trans "Öffnen" %}</span>
|
<h2>{% trans "Eigene Abschnitte" %}</h2>
|
||||||
|
<p class="options-sub">{% trans "Erweitern Sie den Workflow um eigene inhaltliche Blöcke." %}</p>
|
||||||
|
</div>
|
||||||
|
<div class="builder-panel-meta">
|
||||||
|
<span class="builder-panel-count">{{ builder_summary.custom_section_count }} {% trans "eigene Abschnitte" %}</span>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</summary>
|
|
||||||
<div class="nested-accordion-body">
|
|
||||||
<form class="builder-entity-form" method="post" action="/admin-tools/form-builder/?form_type={{ form_type }}&option_category={{ selected_option_category }}">
|
<form class="builder-entity-form" method="post" action="/admin-tools/form-builder/?form_type={{ form_type }}&option_category={{ selected_option_category }}">
|
||||||
{% csrf_token %}
|
{% csrf_token %}
|
||||||
<input type="hidden" name="builder_action" value="add_custom_section" />
|
<input type="hidden" name="builder_action" value="add_custom_section" />
|
||||||
@@ -496,13 +682,16 @@
|
|||||||
<div>
|
<div>
|
||||||
<strong>{{ item.title }}</strong>
|
<strong>{{ item.title }}</strong>
|
||||||
<div class="entity-meta">{{ item.section_key }}</div>
|
<div class="entity-meta">{{ item.section_key }}</div>
|
||||||
|
<div class="builder-inline-meta">
|
||||||
|
<span class="badge">{{ item.custom_field_count }} {% trans "Feld/Felder" %}</span>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="builder-card-head-actions">
|
<div class="builder-card-head-actions">
|
||||||
<label class="builder-switch">
|
<label class="builder-switch">
|
||||||
<input type="checkbox" name="custom_section_is_active_{{ item.id }}" {% if item.is_active %}checked{% endif %} />
|
<input type="checkbox" name="custom_section_is_active_{{ item.id }}" {% if item.is_active %}checked{% endif %} />
|
||||||
<span>{% trans "Aktiv" %}</span>
|
<span>{% trans "Aktiv" %}</span>
|
||||||
</label>
|
</label>
|
||||||
<button class="btn btn-secondary" type="submit" name="delete_custom_section_id" value="{{ item.id }}" data-confirm="{% trans 'Eigenen Abschnitt wirklich löschen? Zugehörige eigene Felder werden ebenfalls entfernt.' %}">{% trans "Löschen" %}</button>
|
<button class="btn btn-secondary" type="submit" name="delete_custom_section_id" value="{{ item.id }}" data-confirm="{% blocktrans trimmed with count=item.custom_field_count %}Eigenen Abschnitt wirklich löschen? {{ count }} zugehörige eigene Felder werden ebenfalls entfernt.{% endblocktrans %}">{% trans "Löschen" %}</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="builder-entity-grid">
|
<div class="builder-entity-grid">
|
||||||
@@ -524,22 +713,25 @@
|
|||||||
<div class="builder-empty-state">{% trans "Keine eigenen Abschnitte vorhanden." %}</div>
|
<div class="builder-empty-state">{% trans "Keine eigenen Abschnitte vorhanden." %}</div>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</div>
|
</div>
|
||||||
<div class="options-actions">
|
<div class="options-actions options-actions-sticky">
|
||||||
<button class="btn btn-primary" type="submit" name="builder_action" value="save_custom_sections">{% trans "Abschnitte speichern" %}</button>
|
<button class="btn btn-primary" type="submit" name="builder_action" value="save_custom_sections">{% trans "Abschnitte speichern" %}</button>
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
</details>
|
</section>
|
||||||
{% endif %}
|
{% elif active_module == 'custom-fields' %}
|
||||||
|
|
||||||
<details class="options-panel nested-accordion js-single-accordion" data-accordion-group="builder-content-subpanels" {% if active_subpanel == 'custom-fields' %}open{% endif %}>
|
<section class="options-panel builder-module-card">
|
||||||
<summary class="nested-accordion-summary">
|
<div class="module-card-body">
|
||||||
<div class="options-head">
|
<div class="options-head">
|
||||||
<h2>{% trans "Eigene Felder" %}</h2>
|
<div class="options-copy">
|
||||||
<span class="builder-panel-toggle">{% trans "Öffnen" %}</span>
|
<h2>{% trans "Eigene Felder" %}</h2>
|
||||||
|
<p class="options-sub">{% trans "Erstellen Sie zusätzliche Eingaben innerhalb bestehender oder eigener Abschnitte." %}</p>
|
||||||
|
</div>
|
||||||
|
<div class="builder-panel-meta">
|
||||||
|
<span class="builder-panel-count">{{ builder_summary.custom_field_count }} {% trans "eigene Felder" %}</span>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</summary>
|
|
||||||
<div class="nested-accordion-body">
|
|
||||||
<form class="builder-entity-form" method="post" action="/admin-tools/form-builder/?form_type={{ form_type }}&option_category={{ selected_option_category }}">
|
<form class="builder-entity-form" method="post" action="/admin-tools/form-builder/?form_type={{ form_type }}&option_category={{ selected_option_category }}">
|
||||||
{% csrf_token %}
|
{% csrf_token %}
|
||||||
<input type="hidden" name="builder_action" value="add_custom_field" />
|
<input type="hidden" name="builder_action" value="add_custom_field" />
|
||||||
@@ -606,8 +798,20 @@
|
|||||||
|
|
||||||
<form method="post" action="/admin-tools/form-builder/?form_type={{ form_type }}&option_category={{ selected_option_category }}">
|
<form method="post" action="/admin-tools/form-builder/?form_type={{ form_type }}&option_category={{ selected_option_category }}">
|
||||||
{% csrf_token %}
|
{% csrf_token %}
|
||||||
|
<input type="hidden" name="custom_fields_section" value="{{ active_custom_fields_section }}" />
|
||||||
|
<nav class="structure-section-nav" aria-label="{% trans 'Eigene Feld-Abschnitte' %}">
|
||||||
|
{% for group in custom_field_groups %}
|
||||||
|
<a class="structure-section-pill{% if active_custom_fields_section == group.key %} is-active{% endif %}" href="/admin-tools/form-builder/?form_type={{ form_type }}&option_category={{ selected_option_category }}&module=custom-fields&custom_fields_section={{ group.key }}">
|
||||||
|
<span class="structure-section-pill-copy">
|
||||||
|
<strong>{{ group.title }}</strong>
|
||||||
|
<span>{% blocktrans trimmed with count=group.items|length %}{{ count }} Feld/Felder{% endblocktrans %}</span>
|
||||||
|
</span>
|
||||||
|
</a>
|
||||||
|
{% endfor %}
|
||||||
|
</nav>
|
||||||
<div class="builder-group-stack">
|
<div class="builder-group-stack">
|
||||||
{% for group in custom_field_groups %}
|
{% for group in custom_field_groups %}
|
||||||
|
{% if active_custom_fields_section == group.key %}
|
||||||
<section class="builder-group-card">
|
<section class="builder-group-card">
|
||||||
<div class="builder-group-head">
|
<div class="builder-group-head">
|
||||||
<h3>{{ group.title }}</h3>
|
<h3>{{ group.title }}</h3>
|
||||||
@@ -686,23 +890,25 @@
|
|||||||
{% endfor %}
|
{% endfor %}
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
|
{% endif %}
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</div>
|
</div>
|
||||||
<div class="options-actions">
|
<div class="options-actions options-actions-sticky">
|
||||||
<button class="btn btn-primary" type="submit" name="builder_action" value="save_custom_fields">{% trans "Eigene Felder speichern" %}</button>
|
<button class="btn btn-primary" type="submit" name="builder_action" value="save_custom_fields">{% trans "Eigene Felder speichern" %}</button>
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
</details>
|
</section>
|
||||||
|
{% elif active_module == 'preview' %}
|
||||||
|
|
||||||
<details class="options-panel nested-accordion js-single-accordion" data-accordion-group="builder-content-subpanels" {% if active_subpanel == 'preview' %}open{% endif %}>
|
<section class="options-panel builder-module-card">
|
||||||
<summary class="nested-accordion-summary">
|
<div class="module-card-body">
|
||||||
<div class="options-head">
|
<div class="options-head">
|
||||||
<h2>{% trans "Live-Vorschau" %}</h2>
|
<div class="options-copy">
|
||||||
<span class="builder-panel-toggle">{% trans "Öffnen" %}</span>
|
<h2>{% trans "Live-Vorschau" %}</h2>
|
||||||
|
<p class="options-sub">{% trans "So wirkt die aktuelle Struktur für das aktive Formular." %}</p>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</summary>
|
|
||||||
<div class="nested-accordion-body">
|
|
||||||
<div class="preview-shell preview-shell-compact">
|
<div class="preview-shell preview-shell-compact">
|
||||||
{% for section in preview_sections %}
|
{% for section in preview_sections %}
|
||||||
<section class="preview-section">
|
<section class="preview-section">
|
||||||
@@ -721,27 +927,16 @@
|
|||||||
{% endfor %}
|
{% endfor %}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</details>
|
</section>
|
||||||
|
{% endif %}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</details>
|
</section>
|
||||||
|
</main>
|
||||||
|
</div>
|
||||||
|
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
{% block extra_scripts %}
|
{% block extra_scripts %}
|
||||||
<script src="{% static 'workflows/js/form_builder.js' %}"></script>
|
<script src="{% static 'workflows/js/form_builder.js' %}"></script>
|
||||||
<script>
|
|
||||||
(() => {
|
|
||||||
const accordions = document.querySelectorAll('.js-single-accordion[data-accordion-group]');
|
|
||||||
accordions.forEach((accordion) => {
|
|
||||||
accordion.addEventListener('toggle', () => {
|
|
||||||
if (!accordion.open) return;
|
|
||||||
const group = accordion.dataset.accordionGroup;
|
|
||||||
document.querySelectorAll(`.js-single-accordion[data-accordion-group="${group}"]`).forEach((peer) => {
|
|
||||||
if (peer !== accordion) peer.open = false;
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
})();
|
|
||||||
</script>
|
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|||||||
@@ -2189,6 +2189,13 @@ def form_builder_page(request):
|
|||||||
active_panel = (request.GET.get('panel') or '').strip()
|
active_panel = (request.GET.get('panel') or '').strip()
|
||||||
active_subpanel = (request.GET.get('subpanel') or '').strip()
|
active_subpanel = (request.GET.get('subpanel') or '').strip()
|
||||||
active_rules_panel = (request.GET.get('rules_panel') or '').strip()
|
active_rules_panel = (request.GET.get('rules_panel') or '').strip()
|
||||||
|
active_module = (request.GET.get('module') or '').strip()
|
||||||
|
active_structure_section = (request.GET.get('structure_section') or '').strip()
|
||||||
|
active_field_rules_section = ((request.POST.get('field_rules_section') if request.method == 'POST' else '') or request.GET.get('field_rules_section') or '').strip()
|
||||||
|
active_field_texts_section = ((request.POST.get('field_texts_section') if request.method == 'POST' else '') or request.GET.get('field_texts_section') or '').strip()
|
||||||
|
active_custom_fields_section = ((request.POST.get('custom_fields_section') if request.method == 'POST' else '') or request.GET.get('custom_fields_section') or '').strip()
|
||||||
|
active_section_rules_section = ((request.POST.get('section_rules_section') if request.method == 'POST' else '') or request.GET.get('section_rules_section') or '').strip()
|
||||||
|
active_conditional_target = ((request.POST.get('conditional_target') if request.method == 'POST' else '') or request.GET.get('conditional_target') or '').strip()
|
||||||
if form_type not in DEFAULT_FIELD_ORDER:
|
if form_type not in DEFAULT_FIELD_ORDER:
|
||||||
form_type = 'onboarding'
|
form_type = 'onboarding'
|
||||||
option_category = request.GET.get('option_category', 'department')
|
option_category = request.GET.get('option_category', 'department')
|
||||||
@@ -2196,6 +2203,34 @@ def form_builder_page(request):
|
|||||||
if option_category not in option_categories:
|
if option_category not in option_categories:
|
||||||
option_category = option_categories[0]
|
option_category = option_categories[0]
|
||||||
|
|
||||||
|
valid_modules = {
|
||||||
|
'structure',
|
||||||
|
'section-rules',
|
||||||
|
'field-rules',
|
||||||
|
'conditional-rules',
|
||||||
|
'options',
|
||||||
|
'field-texts',
|
||||||
|
'custom-sections',
|
||||||
|
'custom-fields',
|
||||||
|
'preview',
|
||||||
|
}
|
||||||
|
|
||||||
|
if not active_module:
|
||||||
|
if active_panel == 'builder-structure':
|
||||||
|
active_module = 'structure'
|
||||||
|
elif active_panel == 'builder-rules':
|
||||||
|
active_module = active_rules_panel or 'section-rules'
|
||||||
|
elif active_panel == 'builder-content':
|
||||||
|
active_module = active_subpanel or 'options'
|
||||||
|
else:
|
||||||
|
active_module = 'structure'
|
||||||
|
if active_module not in valid_modules:
|
||||||
|
active_module = 'structure'
|
||||||
|
if form_type != 'onboarding' and active_module == 'custom-sections':
|
||||||
|
active_module = 'options'
|
||||||
|
if form_type != 'onboarding' and active_module == 'conditional-rules':
|
||||||
|
active_module = 'field-rules'
|
||||||
|
|
||||||
if request.method == 'POST':
|
if request.method == 'POST':
|
||||||
delete_option_id = request.POST.get('delete_option_id', '').strip()
|
delete_option_id = request.POST.get('delete_option_id', '').strip()
|
||||||
delete_custom_field_id = request.POST.get('delete_custom_field_id', '').strip()
|
delete_custom_field_id = request.POST.get('delete_custom_field_id', '').strip()
|
||||||
@@ -2211,7 +2246,7 @@ def form_builder_page(request):
|
|||||||
option.delete()
|
option.delete()
|
||||||
_audit(request, 'form_option_deleted', target_type='form_option', target_id=deleted_id, target_label=deleted_label)
|
_audit(request, 'form_option_deleted', target_type='form_option', target_id=deleted_id, target_label=deleted_label)
|
||||||
messages.success(request, 'Option wurde gelöscht.')
|
messages.success(request, 'Option wurde gelöscht.')
|
||||||
return redirect(f"/admin-tools/form-builder/?form_type={form_type}&option_category={option_category}&panel=builder-content&subpanel=options#builder-content")
|
return redirect(f"/admin-tools/form-builder/?form_type={form_type}&option_category={option_category}&module=options")
|
||||||
if delete_custom_field_id:
|
if delete_custom_field_id:
|
||||||
custom_field = FormCustomFieldConfig.objects.filter(id=delete_custom_field_id, form_type=form_type).first()
|
custom_field = FormCustomFieldConfig.objects.filter(id=delete_custom_field_id, form_type=form_type).first()
|
||||||
if not custom_field:
|
if not custom_field:
|
||||||
@@ -2222,7 +2257,7 @@ def form_builder_page(request):
|
|||||||
custom_field.delete()
|
custom_field.delete()
|
||||||
_audit(request, 'form_custom_field_deleted', target_type='form_custom_field', target_id=deleted_id, target_label=deleted_label)
|
_audit(request, 'form_custom_field_deleted', target_type='form_custom_field', target_id=deleted_id, target_label=deleted_label)
|
||||||
messages.success(request, 'Benutzerdefiniertes Feld wurde gelöscht.')
|
messages.success(request, 'Benutzerdefiniertes Feld wurde gelöscht.')
|
||||||
return redirect(f"/admin-tools/form-builder/?form_type={form_type}&option_category={option_category}&panel=builder-content&subpanel=custom-fields#builder-content")
|
return redirect(f"/admin-tools/form-builder/?form_type={form_type}&option_category={option_category}&module=custom-fields")
|
||||||
if delete_custom_section_id:
|
if delete_custom_section_id:
|
||||||
custom_section = FormCustomSectionConfig.objects.filter(id=delete_custom_section_id, form_type=form_type).first()
|
custom_section = FormCustomSectionConfig.objects.filter(id=delete_custom_section_id, form_type=form_type).first()
|
||||||
if not custom_section:
|
if not custom_section:
|
||||||
@@ -2250,7 +2285,7 @@ def form_builder_page(request):
|
|||||||
details={'section_key': section_key, 'deleted_field_count': deleted_field_count},
|
details={'section_key': section_key, 'deleted_field_count': deleted_field_count},
|
||||||
)
|
)
|
||||||
messages.success(request, 'Benutzerdefinierter Abschnitt wurde gelöscht.')
|
messages.success(request, 'Benutzerdefinierter Abschnitt wurde gelöscht.')
|
||||||
return redirect(f"/admin-tools/form-builder/?form_type={form_type}&option_category={option_category}&panel=builder-content&subpanel=custom-sections#builder-content")
|
return redirect(f"/admin-tools/form-builder/?form_type={form_type}&option_category={option_category}&module=custom-sections")
|
||||||
|
|
||||||
action = request.POST.get('builder_action', '')
|
action = request.POST.get('builder_action', '')
|
||||||
if action == 'add_option':
|
if action == 'add_option':
|
||||||
@@ -2301,7 +2336,7 @@ def form_builder_page(request):
|
|||||||
option.save(update_fields=['label', 'label_en', 'value', 'is_active', 'sort_order'])
|
option.save(update_fields=['label', 'label_en', 'value', 'is_active', 'sort_order'])
|
||||||
except IntegrityError:
|
except IntegrityError:
|
||||||
messages.error(request, f'Doppelte Bezeichnung in Kategorie: {next_label}')
|
messages.error(request, f'Doppelte Bezeichnung in Kategorie: {next_label}')
|
||||||
return redirect(f"/admin-tools/form-builder/?form_type={form_type}&option_category={option.category}&panel=builder-content&subpanel=options#builder-content")
|
return redirect(f"/admin-tools/form-builder/?form_type={form_type}&option_category={option.category}&module=options")
|
||||||
option_category = option.category
|
option_category = option.category
|
||||||
_audit(request, 'form_options_saved', target_type='form_option', target_label=option_category, details={'count': len(option_ids)})
|
_audit(request, 'form_options_saved', target_type='form_option', target_label=option_category, details={'count': len(option_ids)})
|
||||||
messages.success(request, 'Optionen wurden gespeichert.')
|
messages.success(request, 'Optionen wurden gespeichert.')
|
||||||
@@ -2447,7 +2482,7 @@ def form_builder_page(request):
|
|||||||
cfg.select_options_en = (request.POST.get(f'custom_select_options_en_{cfg.id}') or '').strip()
|
cfg.select_options_en = (request.POST.get(f'custom_select_options_en_{cfg.id}') or '').strip()
|
||||||
if cfg.field_type == FormCustomFieldConfig.FIELD_TYPE_SELECT and not cfg.select_options:
|
if cfg.field_type == FormCustomFieldConfig.FIELD_TYPE_SELECT and not cfg.select_options:
|
||||||
messages.error(request, f'Auswahlfeld "{cfg.label}" benötigt mindestens eine Option.')
|
messages.error(request, f'Auswahlfeld "{cfg.label}" benötigt mindestens eine Option.')
|
||||||
return redirect(f"/admin-tools/form-builder/?form_type={form_type}&option_category={option_category}&panel=builder-content&subpanel=custom-fields#builder-content")
|
return redirect(f"/admin-tools/form-builder/?form_type={form_type}&option_category={option_category}&module=custom-fields")
|
||||||
cfg.save()
|
cfg.save()
|
||||||
updated += 1
|
updated += 1
|
||||||
_audit(request, 'form_custom_fields_saved', target_type='form_custom_field', target_label=form_type, details={'count': updated})
|
_audit(request, 'form_custom_fields_saved', target_type='form_custom_field', target_label=form_type, details={'count': updated})
|
||||||
@@ -2536,40 +2571,43 @@ def form_builder_page(request):
|
|||||||
elif action == 'apply_preset':
|
elif action == 'apply_preset':
|
||||||
preset_key = (request.POST.get('preset_key') or '').strip()
|
preset_key = (request.POST.get('preset_key') or '').strip()
|
||||||
if apply_form_preset(form_type, preset_key):
|
if apply_form_preset(form_type, preset_key):
|
||||||
active_panel = 'builder-content'
|
active_module = 'preview'
|
||||||
active_subpanel = 'preview'
|
|
||||||
_audit(request, 'form_preset_applied', target_type='form_config', target_label=form_type, details={'preset': preset_key})
|
_audit(request, 'form_preset_applied', target_type='form_config', target_label=form_type, details={'preset': preset_key})
|
||||||
messages.success(request, 'Preset wurde angewendet.')
|
messages.success(request, 'Preset wurde angewendet.')
|
||||||
else:
|
else:
|
||||||
messages.error(request, 'Preset konnte nicht angewendet werden.')
|
messages.error(request, 'Preset konnte nicht angewendet werden.')
|
||||||
|
|
||||||
if action in {'add_option', 'save_options', 'save_field_texts', 'add_custom_field', 'save_custom_fields', 'add_custom_section', 'save_custom_sections'}:
|
|
||||||
active_panel = 'builder-content'
|
|
||||||
if action in {'add_option', 'save_options'}:
|
if action in {'add_option', 'save_options'}:
|
||||||
active_subpanel = 'options'
|
active_module = 'options'
|
||||||
elif action == 'save_field_texts':
|
elif action == 'save_field_texts':
|
||||||
active_subpanel = 'field-texts'
|
active_module = 'field-texts'
|
||||||
elif action in {'add_custom_field', 'save_custom_fields'}:
|
elif action in {'add_custom_field', 'save_custom_fields'}:
|
||||||
active_subpanel = 'custom-fields'
|
active_module = 'custom-fields'
|
||||||
elif action in {'add_custom_section', 'save_custom_sections'}:
|
elif action in {'add_custom_section', 'save_custom_sections'}:
|
||||||
active_subpanel = 'custom-sections'
|
active_module = 'custom-sections'
|
||||||
elif action in {'save_field_rules', 'save_section_rules', 'save_conditional_rules'}:
|
elif action in {'save_field_rules', 'save_section_rules', 'save_conditional_rules'}:
|
||||||
active_panel = 'builder-rules'
|
active_module = 'section-rules'
|
||||||
if action == 'save_section_rules':
|
if action == 'save_section_rules':
|
||||||
active_rules_panel = 'section-rules'
|
active_module = 'section-rules'
|
||||||
elif action == 'save_field_rules':
|
elif action == 'save_field_rules':
|
||||||
active_rules_panel = 'field-rules'
|
active_module = 'field-rules'
|
||||||
elif action == 'save_conditional_rules':
|
elif action == 'save_conditional_rules':
|
||||||
active_rules_panel = 'conditional-rules'
|
active_module = 'conditional-rules'
|
||||||
redirect_target = f"/admin-tools/form-builder/?form_type={form_type}&option_category={option_category}"
|
redirect_target = f"/admin-tools/form-builder/?form_type={form_type}&option_category={option_category}"
|
||||||
if active_panel:
|
if active_module:
|
||||||
redirect_target += f"&panel={active_panel}"
|
redirect_target += f"&module={active_module}"
|
||||||
if active_subpanel:
|
if active_structure_section:
|
||||||
redirect_target += f"&subpanel={active_subpanel}"
|
redirect_target += f"&structure_section={active_structure_section}"
|
||||||
if active_rules_panel:
|
if active_section_rules_section and active_module == 'section-rules':
|
||||||
redirect_target += f"&rules_panel={active_rules_panel}"
|
redirect_target += f"§ion_rules_section={active_section_rules_section}"
|
||||||
if anchor == 'builder-content' or active_panel == 'builder-content':
|
if active_field_rules_section and active_module == 'field-rules':
|
||||||
redirect_target += "#builder-content"
|
redirect_target += f"&field_rules_section={active_field_rules_section}"
|
||||||
|
if active_conditional_target and active_module == 'conditional-rules':
|
||||||
|
redirect_target += f"&conditional_target={active_conditional_target}"
|
||||||
|
if active_field_texts_section and active_module == 'field-texts':
|
||||||
|
redirect_target += f"&field_texts_section={active_field_texts_section}"
|
||||||
|
if active_custom_fields_section and active_module == 'custom-fields':
|
||||||
|
redirect_target += f"&custom_fields_section={active_custom_fields_section}"
|
||||||
return redirect(redirect_target)
|
return redirect(redirect_target)
|
||||||
|
|
||||||
default_names = list(DEFAULT_FIELD_ORDER.get(form_type, []))
|
default_names = list(DEFAULT_FIELD_ORDER.get(form_type, []))
|
||||||
@@ -2700,6 +2738,8 @@ def form_builder_page(request):
|
|||||||
|
|
||||||
section_rule_items = []
|
section_rule_items = []
|
||||||
if section_order:
|
if section_order:
|
||||||
|
if active_structure_section not in section_order:
|
||||||
|
active_structure_section = section_order[0]
|
||||||
fallback_section = section_order[-1] if section_order else ''
|
fallback_section = section_order[-1] if section_order else ''
|
||||||
custom_section_map = {cfg.section_key: cfg for cfg in custom_section_configs}
|
custom_section_map = {cfg.section_key: cfg for cfg in custom_section_configs}
|
||||||
for key in section_order:
|
for key in section_order:
|
||||||
@@ -2717,6 +2757,9 @@ def form_builder_page(request):
|
|||||||
'field_count': len([c for c in configs if (c.page_key or default_page_map.get(c.field_name, fallback_section)) == key]) + len([c for c in custom_field_configs if c.section_key == key]),
|
'field_count': len([c for c in configs if (c.page_key or default_page_map.get(c.field_name, fallback_section)) == key]) + len([c for c in custom_field_configs if c.section_key == key]),
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
section_rule_keys = [item['key'] for item in section_rule_items]
|
||||||
|
if section_rule_keys and active_section_rules_section not in section_rule_keys:
|
||||||
|
active_section_rules_section = section_rule_keys[0]
|
||||||
|
|
||||||
field_rule_items = []
|
field_rule_items = []
|
||||||
for cfg in configs:
|
for cfg in configs:
|
||||||
@@ -2747,6 +2790,11 @@ def form_builder_page(request):
|
|||||||
'items': grouped_custom.get(key, []),
|
'items': grouped_custom.get(key, []),
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
custom_section_field_counts: dict[str, int] = {}
|
||||||
|
for cfg in custom_field_configs:
|
||||||
|
custom_section_field_counts[cfg.section_key] = custom_section_field_counts.get(cfg.section_key, 0) + 1
|
||||||
|
for cfg in custom_section_configs:
|
||||||
|
cfg.custom_field_count = custom_section_field_counts.get(cfg.section_key, 0)
|
||||||
|
|
||||||
field_rule_groups = []
|
field_rule_groups = []
|
||||||
if section_order:
|
if section_order:
|
||||||
@@ -2761,6 +2809,9 @@ def form_builder_page(request):
|
|||||||
'items': grouped_rules.get(key, []),
|
'items': grouped_rules.get(key, []),
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
field_rule_group_keys = [group['key'] for group in field_rule_groups]
|
||||||
|
if field_rule_group_keys and active_field_rules_section not in field_rule_group_keys:
|
||||||
|
active_field_rules_section = field_rule_group_keys[0]
|
||||||
|
|
||||||
field_text_groups = []
|
field_text_groups = []
|
||||||
if section_order:
|
if section_order:
|
||||||
@@ -2776,6 +2827,12 @@ def form_builder_page(request):
|
|||||||
'items': grouped_texts.get(key, []),
|
'items': grouped_texts.get(key, []),
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
field_text_group_keys = [group['key'] for group in field_text_groups]
|
||||||
|
if field_text_group_keys and active_field_texts_section not in field_text_group_keys:
|
||||||
|
active_field_texts_section = field_text_group_keys[0]
|
||||||
|
custom_field_group_keys = [group['key'] for group in custom_field_groups]
|
||||||
|
if custom_field_group_keys and active_custom_fields_section not in custom_field_group_keys:
|
||||||
|
active_custom_fields_section = custom_field_group_keys[0]
|
||||||
|
|
||||||
conditional_rule_items = []
|
conditional_rule_items = []
|
||||||
if form_type == 'onboarding':
|
if form_type == 'onboarding':
|
||||||
@@ -2837,6 +2894,9 @@ def form_builder_page(request):
|
|||||||
'target_fields': target_fields,
|
'target_fields': target_fields,
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
conditional_rule_keys = [item['target_key'] for item in conditional_rule_items]
|
||||||
|
if conditional_rule_keys and active_conditional_target not in conditional_rule_keys:
|
||||||
|
active_conditional_target = conditional_rule_keys[0]
|
||||||
|
|
||||||
preview_sections = []
|
preview_sections = []
|
||||||
if section_order:
|
if section_order:
|
||||||
@@ -2906,6 +2966,13 @@ def form_builder_page(request):
|
|||||||
'active_panel': active_panel,
|
'active_panel': active_panel,
|
||||||
'active_subpanel': active_subpanel,
|
'active_subpanel': active_subpanel,
|
||||||
'active_rules_panel': active_rules_panel,
|
'active_rules_panel': active_rules_panel,
|
||||||
|
'active_module': active_module,
|
||||||
|
'active_structure_section': active_structure_section,
|
||||||
|
'active_field_rules_section': active_field_rules_section,
|
||||||
|
'active_field_texts_section': active_field_texts_section,
|
||||||
|
'active_custom_fields_section': active_custom_fields_section,
|
||||||
|
'active_section_rules_section': active_section_rules_section,
|
||||||
|
'active_conditional_target': active_conditional_target,
|
||||||
'available_presets': FORM_PRESETS.get(form_type, {}),
|
'available_presets': FORM_PRESETS.get(form_type, {}),
|
||||||
'can_override_locked_builder_rules': can_override_locked_builder_rules,
|
'can_override_locked_builder_rules': can_override_locked_builder_rules,
|
||||||
},
|
},
|
||||||
|
|||||||
Reference in New Issue
Block a user