fix(ui): Header während der ersten Recherche bedienbar halten

Das blockierende Fortschritts-Overlay (.progress-overlay.blocking) liegt
position:fixed über dem gesamten Viewport und schluckt damit auch die
Klicks auf den globalen Header. Beim ersten Durchlauf eines Falls waren so
Barrierefreiheit, Theme-Wechsel, Konto-Menü inkl. Org-Switcher und
Abmelden nicht erreichbar.

Neue Body-Klasse first-refresh-blocking hebt den Header per z-index über
das Overlay, solange dieses blockierend sichtbar ist. UI._syncHeaderAccess()
spiegelt den Overlay-Zustand an allen Stellen, die das Overlay ein- oder
ausblenden.

Die fallbezogenen Aktionen (Aktualisieren, Bearbeiten, ...) bleiben
unverändert gesperrt: dafür sorgen weiterhin #incident-view.refresh-blurred
und .incident-header-actions.first-refresh-locked.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Dieser Commit ist enthalten in:
claude-dev
2026-07-23 20:55:46 +00:00
Ursprung 3a3076c4cf
Commit e3b4e25429
4 geänderte Dateien mit 33 neuen und 3 gelöschten Zeilen

Datei anzeigen

@@ -2144,6 +2144,14 @@ a.dev-source-pill:hover {
pointer-events: auto; pointer-events: auto;
background: rgba(0,0,0,0.15); background: rgba(0,0,0,0.15);
} }
/* Der globale Header bleibt auch während der ersten (blockierenden) Recherche
bedienbar. Das Overlay deckt sonst den gesamten Viewport ab und schluckt die
Klicks auf Barrierefreiheit, Theme-Wechsel, Konto-Menü und Abmelden.
Gesperrt bleiben ausschließlich die fallbezogenen Aktionen (Aktualisieren,
Bearbeiten, ...) über #incident-view.refresh-blurred. */
body.first-refresh-blocking .header {
z-index: 9100;
}
.progress-popup { .progress-popup {
pointer-events: auto; pointer-events: auto;
background: var(--bg-primary); background: var(--bg-primary);

Datei anzeigen

@@ -13,7 +13,7 @@
<link rel="stylesheet" href="/static/vendor/leaflet.css"> <link rel="stylesheet" href="/static/vendor/leaflet.css">
<link rel="stylesheet" href="/static/vendor/MarkerCluster.css"> <link rel="stylesheet" href="/static/vendor/MarkerCluster.css">
<link rel="stylesheet" href="/static/vendor/MarkerCluster.Default.css"> <link rel="stylesheet" href="/static/vendor/MarkerCluster.Default.css">
<link rel="stylesheet" href="/static/css/style.css?v=20260522c"> <link rel="stylesheet" href="/static/css/style.css?v=20260723a">
<style> <style>
/* Export Modal Radio */ /* Export Modal Radio */
.export-radio { display:flex; align-items:center; gap:10px; padding:8px 12px; cursor:pointer; border-radius:var(--radius-sm); transition:background 0.15s; border:1px solid transparent; margin-bottom:4px; } .export-radio { display:flex; align-items:center; gap:10px; padding:8px 12px; cursor:pointer; border-radius:var(--radius-sm); transition:background 0.15s; border:1px solid transparent; margin-bottom:4px; }
@@ -808,10 +808,10 @@
<script src="/static/js/i18n.js?v=20260513a"></script> <script src="/static/js/i18n.js?v=20260513a"></script>
<script src="/static/js/api.js?v=20260522f"></script> <script src="/static/js/api.js?v=20260522f"></script>
<script src="/static/js/ws.js?v=20260316b"></script> <script src="/static/js/ws.js?v=20260316b"></script>
<script src="/static/js/components.js?v=20260522d"></script> <script src="/static/js/components.js?v=20260723a"></script>
<script src="/static/js/layout.js?v=20260513f"></script> <script src="/static/js/layout.js?v=20260513f"></script>
<script src="/static/js/pipeline.js?v=20260513d"></script> <script src="/static/js/pipeline.js?v=20260513d"></script>
<script src="/static/js/app.js?v=20260522f"></script> <script src="/static/js/app.js?v=20260723a"></script>
<script src="/static/js/cluster-data.js?v=20260322f"></script> <script src="/static/js/cluster-data.js?v=20260322f"></script>
<script src="/static/js/tutorial.js?v=20260316z"></script> <script src="/static/js/tutorial.js?v=20260316z"></script>
<script src="/static/js/chat.js?v=20260514e"></script> <script src="/static/js/chat.js?v=20260514e"></script>

Datei anzeigen

@@ -784,6 +784,7 @@ const App = {
// Hide any popup/mini from previous incident // Hide any popup/mini from previous incident
const prevOverlay = document.getElementById('progress-overlay'); const prevOverlay = document.getElementById('progress-overlay');
if (prevOverlay) prevOverlay.style.display = 'none'; if (prevOverlay) prevOverlay.style.display = 'none';
if (typeof UI !== 'undefined' && UI._syncHeaderAccess) UI._syncHeaderAccess();
const prevMini = document.getElementById('progress-mini'); const prevMini = document.getElementById('progress-mini');
if (prevMini) prevMini.style.display = 'none'; if (prevMini) prevMini.style.display = 'none';
const blurTarget = document.getElementById('incident-view'); const blurTarget = document.getElementById('incident-view');
@@ -2596,6 +2597,7 @@ async handleRefresh() {
// Temporarily hide progress popup so confirm dialog is fully visible // Temporarily hide progress popup so confirm dialog is fully visible
const progressOverlay = document.getElementById('progress-overlay'); const progressOverlay = document.getElementById('progress-overlay');
if (progressOverlay) progressOverlay.style.display = 'none'; if (progressOverlay) progressOverlay.style.display = 'none';
UI._syncHeaderAccess();
const ok = await confirmDialog((typeof T === 'function' ? T('confirm.cancel_running_research', 'Laufende Recherche abbrechen?') : 'Laufende Recherche abbrechen?')); const ok = await confirmDialog((typeof T === 'function' ? T('confirm.cancel_running_research', 'Laufende Recherche abbrechen?') : 'Laufende Recherche abbrechen?'));
@@ -2603,11 +2605,13 @@ async handleRefresh() {
if (!ok) { if (!ok) {
const state = UI._progressState[this.currentIncidentId]; const state = UI._progressState[this.currentIncidentId];
if (state && progressOverlay) progressOverlay.style.display = 'flex'; if (state && progressOverlay) progressOverlay.style.display = 'flex';
UI._syncHeaderAccess();
return; return;
} }
// Show cancelling state in popup // Show cancelling state in popup
if (progressOverlay) progressOverlay.style.display = 'flex'; if (progressOverlay) progressOverlay.style.display = 'flex';
UI._syncHeaderAccess();
const btn = document.getElementById('progress-cancel-btn'); const btn = document.getElementById('progress-cancel-btn');
if (btn) { if (btn) {
btn.textContent = (typeof T === 'function' ? T('action.cancelling', 'Wird abgebrochen...') : 'Wird abgebrochen...'); btn.textContent = (typeof T === 'function' ? T('action.cancelling', 'Wird abgebrochen...') : 'Wird abgebrochen...');

Datei anzeigen

@@ -355,6 +355,20 @@ const UI = {
this._showPopupProgress(status, extra, state); this._showPopupProgress(status, extra, state);
}, },
/**
* Hält den globalen Header bedienbar, solange das blockierende
* Fortschritts-Overlay sichtbar ist. Die Body-Klasse hebt den Header per
* z-index über das Overlay: Barrierefreiheit, Theme, Konto-Menü und
* Abmelden müssen jederzeit erreichbar sein.
*/
_syncHeaderAccess() {
const overlay = document.getElementById('progress-overlay');
const blocking = !!overlay
&& overlay.classList.contains('blocking')
&& overlay.style.display !== 'none';
document.body.classList.toggle('first-refresh-blocking', blocking);
},
_showPopupProgress(status, extra, state) { _showPopupProgress(status, extra, state) {
const overlay = document.getElementById('progress-overlay'); const overlay = document.getElementById('progress-overlay');
const popup = document.getElementById('progress-popup'); const popup = document.getElementById('progress-popup');
@@ -381,6 +395,7 @@ const UI = {
} else { } else {
overlay.classList.remove('blocking'); overlay.classList.remove('blocking');
} }
this._syncHeaderAccess();
// Minimize button: only for updates (not first) // Minimize button: only for updates (not first)
const minBtn = document.getElementById('progress-popup-minimize'); const minBtn = document.getElementById('progress-popup-minimize');
@@ -485,6 +500,7 @@ const UI = {
// Hide popup // Hide popup
const overlay = document.getElementById('progress-overlay'); const overlay = document.getElementById('progress-overlay');
if (overlay) overlay.style.display = 'none'; if (overlay) overlay.style.display = 'none';
this._syncHeaderAccess();
}, },
minimizeProgress(incidentId) { minimizeProgress(incidentId) {
@@ -528,6 +544,7 @@ const UI = {
overlay.style.display = 'flex'; overlay.style.display = 'flex';
overlay.classList.remove('blocking'); overlay.classList.remove('blocking');
} }
this._syncHeaderAccess();
// Mark all steps done // Mark all steps done
document.querySelectorAll('.progress-check-item').forEach(item => { document.querySelectorAll('.progress-check-item').forEach(item => {
@@ -620,6 +637,7 @@ const UI = {
if (incidentId === App.currentIncidentId) { if (incidentId === App.currentIncidentId) {
const overlay = document.getElementById('progress-overlay'); const overlay = document.getElementById('progress-overlay');
if (overlay) { overlay.style.display = 'none'; overlay.classList.remove('blocking'); } if (overlay) { overlay.style.display = 'none'; overlay.classList.remove('blocking'); }
this._syncHeaderAccess();
const mini = document.getElementById('progress-mini'); const mini = document.getElementById('progress-mini');
if (mini) mini.style.display = 'none'; if (mini) mini.style.display = 'none';
} }