add section Privacy Policy DSGVO

This commit is contained in:
2026-08-05 18:17:22 +00:00
parent bd23858537
commit c9e6438222
12 changed files with 258 additions and 7 deletions
+8
View File
@@ -15,6 +15,7 @@
<button type="button" class="button button-secondary" id="bulk-edit-button" data-base-label="✏ {{ t('assets.bulk_edit', 'Daten ändern')|e }}" disabled>✏ {{ t('assets.bulk_edit', 'Daten ändern') }}</button>
<button type="button" class="button button-danger" id="bulk-delete-button" data-base-label="🗑 {{ t('assets.delete_selected', 'Markierte löschen')|e }}" disabled>🗑 {{ t('assets.delete_selected', 'Markierte löschen') }}</button>
<button type="button" class="button button-secondary" id="merge-duplicates-button" disabled>⧉ {{ t('duplicates.merge', 'Duplikate zusammenführen') }}</button>
<button type="button" class="button button-secondary" id="software-compare-button" disabled>⇄ {{ t('software.compare.button', 'Software vergleichen') }}</button>
<div class="bulk-job-controls" aria-label="{{ t('jobs.bulk.controls_label')|e }}">
<label class="visually-hidden" for="bulk-job-type">{{ t('jobs.type') }}</label>
<select id="bulk-job-type" class="bulk-job-type" disabled>
@@ -65,6 +66,7 @@
<form id="bulk-edit-form" class="hidden-utility-form" method="post" action="/assets/bulk-edit">{% if selected %}<input type="hidden" name="category_id" value="{{ selected.id }}">{% endif %}<span id="bulk-edit-ids"></span></form>
<form id="bulk-delete-form" class="hidden-utility-form" method="post" action="/assets/bulk-delete" onsubmit="return confirm({{ t('assets.bulk_delete_confirm')|tojson }});">{% if selected %}<input type="hidden" name="category_id" value="{{ selected.id }}">{% endif %}<span id="bulk-delete-ids"></span></form>
<form id="merge-duplicates-form" class="hidden-utility-form" method="post" action="/assets/merge"><span id="merge-duplicate-ids"></span></form>
<form id="software-compare-form" class="hidden-utility-form" method="post" action="/assets/software-compare"><span id="software-compare-ids"></span></form>
<form id="bulk-job-form" class="hidden-utility-form" method="post" action="/jobs/bulk-create">
<input type="hidden" name="job_type" id="bulk-job-type-value">
<input type="hidden" name="definition_id" id="bulk-job-definition-value">
@@ -345,6 +347,7 @@
const editButton = document.getElementById('bulk-edit-button');
const deleteButton = document.getElementById('bulk-delete-button');
const mergeButton = document.getElementById('merge-duplicates-button');
const softwareCompareButton = document.getElementById('software-compare-button');
const jobTypeSelect = document.getElementById('bulk-job-type');
const jobStartButton = document.getElementById('bulk-job-start-button');
const isVisible = box => {
@@ -381,6 +384,10 @@
mergeButton.disabled = count < 2;
mergeButton.textContent = count >= 2 ? `⧉ {{ t('duplicates.merge') }} (${count})` : '⧉ {{ t('duplicates.merge') }}';
}
if (softwareCompareButton) {
softwareCompareButton.disabled = count !== 2;
softwareCompareButton.textContent = count === 2 ? `⇄ {{ t('software.compare.button', 'Software vergleichen') }} (2)` : '⇄ {{ t('software.compare.button', 'Software vergleichen') }}';
}
if (jobTypeSelect) { jobTypeSelect.disabled = count === 0; filterJobDefinitions(); }
if (jobStartButton) {
jobStartButton.disabled = count === 0 || !jobTypeSelect?.value;
@@ -404,6 +411,7 @@
editButton?.addEventListener('click', () => submit('bulk-edit-form', 'bulk-edit-ids'));
deleteButton?.addEventListener('click', () => submit('bulk-delete-form', 'bulk-delete-ids'));
mergeButton?.addEventListener('click', () => submit('merge-duplicates-form', 'merge-duplicate-ids'));
softwareCompareButton?.addEventListener('click', () => submit('software-compare-form', 'software-compare-ids'));
jobTypeSelect?.addEventListener('change', refresh);
jobStartButton?.addEventListener('click', () => {
const count = selected().length;
+2 -2
View File
@@ -22,7 +22,7 @@
{% if session_user %}
<form method="post" action="/profile/theme" class="header-theme-form" id="header-theme-form">
<input type="hidden" name="theme_mode" value="{{ 'light' if theme_mode == 'dark' else 'dark' }}">
<input type="hidden" name="next_url" value="{{ request.url.path }}">
<input type="hidden" name="next_url" value="{{ request.url.path }}{% if request.url.query %}?{{ request.url.query }}{% endif %}">
<button type="submit" class="header-theme-toggle" title="{{ t('appearance.switch_to_light') if theme_mode == 'dark' else t('appearance.switch_to_dark') }}" aria-label="{{ t('appearance.switch_to_light') if theme_mode == 'dark' else t('appearance.switch_to_dark') }}">
<span class="theme-icon-light" aria-hidden="true"></span>
<span class="theme-icon-dark" aria-hidden="true"></span>
@@ -30,7 +30,7 @@
</form>
{% endif %}
<button type="button" class="header-help-button" id="about-dialog-button" title="{{ t('about.open') }}" aria-label="{{ t('about.open') }}">?</button>
<details class="language-menu"><summary>🌐 {{ current_language|upper }} ▾</summary><div class="user-menu-panel">{% for language in available_languages() %}<form method="post" action="/profile/language"><input type="hidden" name="language_code" value="{{ language.code }}"><input type="hidden" name="next_url" value="{{ request.url.path }}"><button type="submit" class="menu-button{% if language.code == current_language %} active{% endif %}">{{ language.native_name }}</button></form>{% endfor %}</div></details>
<details class="language-menu"><summary>🌐 {{ current_language|upper }} ▾</summary><div class="user-menu-panel">{% for language in available_languages() %}<form method="post" action="/profile/language"><input type="hidden" name="language_code" value="{{ language.code }}"><input type="hidden" name="next_url" value="{{ request.url.path }}{% if request.url.query %}?{{ request.url.query }}{% endif %}"><button type="submit" class="menu-button{% if language.code == current_language %} active{% endif %}">{{ language.native_name }}</button></form>{% endfor %}</div></details>
<details class="user-menu"><summary>👤 {{ session_user.display_name if session_user else t('app.guest') }} ▾</summary><div class="user-menu-panel">{% if session_user %}<a href="/profile">{{ t('app.profile') }}</a><a href="/logout">{{ t('app.logout') }}</a>{% else %}{% if auth.get('mode', 'none') == 'none' %}<span class="muted">Authentication disabled</span>{% endif %}<a href="/login">{{ t('app.login') }}</a>{% endif %}</div></details></div>
</header>
<dialog id="about-dialog" class="about-dialog">
+58
View File
@@ -0,0 +1,58 @@
{% extends 'base.html' %}
{% block content %}
<div class="toolbar">
<div>
<h1>{{ t('software.compare.title', 'Softwareinventuren vergleichen') }}</h1>
<p class="muted">{{ t('software.compare.subtitle', 'Vergleich von {asset_a} und {asset_b}', asset_a=asset_a.name, asset_b=asset_b.name) }}</p>
</div>
<div class="toolbar-actions">
<a class="button button-secondary" href="/assets/software-compare/export.xlsx?asset_a={{ asset_a.id }}&asset_b={{ asset_b.id }}&mode={{ mode }}">⇩ {{ t('software.compare.export', 'Als Excel herunterladen') }}</a>
<a class="button button-secondary" href="/assets">{{ t('common.back', 'Zurück') }}</a>
</div>
</div>
<section class="panel">
<form method="get" action="/assets/software-compare" class="form-grid compact-form">
<input type="hidden" name="asset_a" value="{{ asset_a.id }}">
<input type="hidden" name="asset_b" value="{{ asset_b.id }}">
<label>{{ t('software.compare.mode', 'Vergleichsmodus') }}
<select name="mode" onchange="this.form.submit()">
<option value="exact" {% if mode == 'exact' %}selected{% endif %}>{{ t('software.compare.mode.exact', 'Exakter Softwarename') }}</option>
<option value="ignore_version" {% if mode == 'ignore_version' %}selected{% endif %}>{{ t('software.compare.mode.ignore_version', 'Versionen ignorieren') }}</option>
<option value="ignore_version_year" {% if mode == 'ignore_version_year' %}selected{% endif %}>{{ t('software.compare.mode.ignore_version_year', 'Versionen und Jahreszahlen ignorieren') }}</option>
</select>
</label>
</form>
<p class="muted">{{ t('software.compare.mode_help', 'Originalnamen und Versionen bleiben sichtbar. Die Normalisierung wird nur für die Zuordnung verwendet.') }}</p>
<div class="summary-cards compact-summary">
<span class="badge">{{ t('software.compare.only_a', 'Nur auf {asset}', asset=asset_a.name) }}: {{ counts.only_a }}</span>
<span class="badge">{{ t('software.compare.only_b', 'Nur auf {asset}', asset=asset_b.name) }}: {{ counts.only_b }}</span>
<span class="badge">{{ t('software.compare.both', 'Auf beiden vorhanden') }}: {{ counts.both }}</span>
</div>
<div class="table-scroll management-table-scroll">
<table class="data-table" id="software-comparison-table" data-storage-key="software-comparison-table">
<thead><tr>
<th>{{ t('software.compare.comparison_name', 'Vergleichsname') }}</th>
<th>{{ t('software.platform', 'Plattform') }}</th>
<th>{{ t('software.compare.status', 'Vergleichsstatus') }}</th>
<th>{{ asset_a.name }} · {{ t('common.name', 'Name') }}</th>
<th>{{ asset_a.name }} · {{ t('about.version', 'Version') }}</th>
<th>{{ asset_a.name }} · {{ t('software.publisher', 'Hersteller') }}</th>
<th>{{ asset_b.name }} · {{ t('common.name', 'Name') }}</th>
<th>{{ asset_b.name }} · {{ t('about.version', 'Version') }}</th>
<th>{{ asset_b.name }} · {{ t('software.publisher', 'Hersteller') }}</th>
</tr></thead>
<tbody>
{% for row in rows %}
<tr>
<td>{{ row.comparison_name }}</td>
<td>{{ t('software.platform.' ~ row.platform, row.platform) }}</td>
<td><span class="job-status job-status-{% if row.status == 'both' %}success{% else %}pending{% endif %}">{% if row.status == 'both' %}{{ t('software.compare.both', 'Auf beiden vorhanden') }}{% elif row.status == 'only_a' %}{{ t('software.compare.only_a', 'Nur auf {asset}', asset=asset_a.name) }}{% else %}{{ t('software.compare.only_b', 'Nur auf {asset}', asset=asset_b.name) }}{% endif %}</span></td>
<td>{{ row.a_names or '—' }}</td><td>{{ row.a_versions or '—' }}</td><td>{{ row.a_publishers or '—' }}</td>
<td>{{ row.b_names or '—' }}</td><td>{{ row.b_versions or '—' }}</td><td>{{ row.b_publishers or '—' }}</td>
</tr>
{% else %}<tr><td colspan="9">{{ t('software.compare.empty', 'Für diese Assets sind keine Softwareinventuren vorhanden.') }}</td></tr>{% endfor %}
</tbody>
</table>
</div>
</section>
{% endblock %}