Zusammenfassung als eigene Dashboard-Kachel
Research-Lagen: ZUSAMMENFASSUNG-Sektion wird aus dem Bericht extrahiert und in eigener Kachel oberhalb des Recherchberichts angezeigt. Der Recherchebericht zeigt den Rest ohne Dopplung. - Neue Kachel mit gs-id="zusammenfassung" im GridStack - Toggle-Button in der Layout-Leiste - extractZusammenfassung() und renderZusammenfassung() in UI - Adhoc/Live-Lagen: Kachel wird automatisch ausgeblendet - Export nutzt weiterhin _extract_zusammenfassung() aus dem Backend
Dieser Commit ist enthalten in:
@@ -193,6 +193,7 @@
|
|||||||
<!-- Layout-Toolbar -->
|
<!-- Layout-Toolbar -->
|
||||||
<div class="layout-toolbar" id="layout-toolbar" style="display:none;">
|
<div class="layout-toolbar" id="layout-toolbar" style="display:none;">
|
||||||
<div class="layout-toggles">
|
<div class="layout-toggles">
|
||||||
|
<button class="layout-toggle-btn active" data-tile="zusammenfassung" onclick="LayoutManager.toggleTile('zusammenfassung')" aria-pressed="true">Zusammenfassung</button>
|
||||||
<button class="layout-toggle-btn active" data-tile="lagebild" onclick="LayoutManager.toggleTile('lagebild')" aria-pressed="true">Lagebild</button>
|
<button class="layout-toggle-btn active" data-tile="lagebild" onclick="LayoutManager.toggleTile('lagebild')" aria-pressed="true">Lagebild</button>
|
||||||
<button class="layout-toggle-btn active" data-tile="faktencheck" onclick="LayoutManager.toggleTile('faktencheck')" aria-pressed="true">Faktencheck</button>
|
<button class="layout-toggle-btn active" data-tile="faktencheck" onclick="LayoutManager.toggleTile('faktencheck')" aria-pressed="true">Faktencheck</button>
|
||||||
<button class="layout-toggle-btn active" data-tile="quellen" onclick="LayoutManager.toggleTile('quellen')" aria-pressed="true">Quellen</button>
|
<button class="layout-toggle-btn active" data-tile="quellen" onclick="LayoutManager.toggleTile('quellen')" aria-pressed="true">Quellen</button>
|
||||||
@@ -204,7 +205,20 @@
|
|||||||
|
|
||||||
<!-- gridstack Dashboard-Grid -->
|
<!-- gridstack Dashboard-Grid -->
|
||||||
<div class="grid-stack">
|
<div class="grid-stack">
|
||||||
<div class="grid-stack-item" gs-id="lagebild" gs-x="0" gs-y="0" gs-w="6" gs-h="4" gs-min-w="4" gs-min-h="4">
|
<div class="grid-stack-item" gs-id="zusammenfassung" gs-x="0" gs-y="0" gs-w="12" gs-h="2" gs-min-w="4" gs-min-h="2">
|
||||||
|
<div class="grid-stack-item-content">
|
||||||
|
<div class="card" id="zusammenfassung-card">
|
||||||
|
<div class="card-header">
|
||||||
|
<div class="card-title clickable" role="button" tabindex="0" onclick="openContentModal('Zusammenfassung', 'zusammenfassung-content')">Zusammenfassung</div>
|
||||||
|
</div>
|
||||||
|
<div id="zusammenfassung-content">
|
||||||
|
<div id="zusammenfassung-text" class="summary-text" style="padding:8px 16px;"></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="grid-stack-item" gs-id="lagebild" gs-x="0" gs-y="2" gs-w="6" gs-h="4" gs-min-w="4" gs-min-h="4">
|
||||||
<div class="grid-stack-item-content">
|
<div class="grid-stack-item-content">
|
||||||
<div class="card incident-analysis-summary">
|
<div class="card incident-analysis-summary">
|
||||||
<div class="card-header">
|
<div class="card-header">
|
||||||
|
|||||||
@@ -755,6 +755,7 @@ const App = {
|
|||||||
el = document.getElementById("incident-title"); if (el) el.textContent = "";
|
el = document.getElementById("incident-title"); if (el) el.textContent = "";
|
||||||
el = document.getElementById("summary-content"); if (el) el.scrollTop = 0;
|
el = document.getElementById("summary-content"); if (el) el.scrollTop = 0;
|
||||||
el = document.getElementById("summary-text"); if (el) el.innerHTML = "";
|
el = document.getElementById("summary-text"); if (el) el.innerHTML = "";
|
||||||
|
el = document.getElementById("zusammenfassung-text"); if (el) el.innerHTML = "";
|
||||||
el = document.getElementById("factcheck-filters"); if (el) el.innerHTML = "";
|
el = document.getElementById("factcheck-filters"); if (el) el.innerHTML = "";
|
||||||
el = document.querySelector(".factcheck-list"); if (el) el.scrollTop = 0;
|
el = document.querySelector(".factcheck-list"); if (el) el.scrollTop = 0;
|
||||||
el = document.getElementById("factcheck-list"); if (el) el.innerHTML = "";
|
el = document.getElementById("factcheck-list"); if (el) el.innerHTML = "";
|
||||||
@@ -842,15 +843,28 @@ const App = {
|
|||||||
deleteBtn.disabled = !isCreator;
|
deleteBtn.disabled = !isCreator;
|
||||||
deleteBtn.title = isCreator ? '' : `Nur ${(incident.created_by_username || '').split('@')[0]} kann diese Lage löschen`;
|
deleteBtn.title = isCreator ? '' : `Nur ${(incident.created_by_username || '').split('@')[0]} kann diese Lage löschen`;
|
||||||
|
|
||||||
// Zusammenfassung mit Quellenverzeichnis
|
// Zusammenfassung-Kachel + Lagebild-Kachel aufteilen
|
||||||
|
const zusammenfassungText = document.getElementById('zusammenfassung-text');
|
||||||
const summaryText = document.getElementById('summary-text');
|
const summaryText = document.getElementById('summary-text');
|
||||||
if (incident.summary) {
|
const zusammenfassungCard = document.getElementById('zusammenfassung-card');
|
||||||
summaryText.innerHTML = UI.renderSummary(
|
|
||||||
incident.summary,
|
if (incident.summary && incident.type === 'research') {
|
||||||
incident.sources_json,
|
const { zusammenfassung, remaining } = UI.extractZusammenfassung(incident.summary);
|
||||||
incident.type
|
if (zusammenfassung) {
|
||||||
);
|
if (zusammenfassungText) zusammenfassungText.innerHTML = UI.renderZusammenfassung(zusammenfassung);
|
||||||
|
if (zusammenfassungCard) zusammenfassungCard.style.display = '';
|
||||||
|
summaryText.innerHTML = UI.renderSummary(remaining, incident.sources_json, incident.type);
|
||||||
} else {
|
} else {
|
||||||
|
if (zusammenfassungText) zusammenfassungText.innerHTML = '<span style="color:var(--text-disabled);">Zusammenfassung wird beim n\u00e4chsten Refresh generiert.</span>';
|
||||||
|
if (zusammenfassungCard) zusammenfassungCard.style.display = '';
|
||||||
|
summaryText.innerHTML = UI.renderSummary(incident.summary, incident.sources_json, incident.type);
|
||||||
|
}
|
||||||
|
} else if (incident.summary) {
|
||||||
|
// Adhoc/Live: Keine Zusammenfassung-Kachel
|
||||||
|
if (zusammenfassungCard) zusammenfassungCard.style.display = 'none';
|
||||||
|
summaryText.innerHTML = UI.renderSummary(incident.summary, incident.sources_json, incident.type);
|
||||||
|
} else {
|
||||||
|
if (zusammenfassungCard) zusammenfassungCard.style.display = 'none';
|
||||||
summaryText.innerHTML = '<span style="color:var(--text-disabled);">Noch keine Zusammenfassung. Klicke auf "Aktualisieren" um die Recherche zu starten.</span>';
|
summaryText.innerHTML = '<span style="color:var(--text-disabled);">Noch keine Zusammenfassung. Klicke auf "Aktualisieren" um die Recherche zu starten.</span>';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -695,6 +695,35 @@ const UI = {
|
|||||||
/**
|
/**
|
||||||
* Zusammenfassung mit Inline-Zitaten und Quellenverzeichnis rendern.
|
* Zusammenfassung mit Inline-Zitaten und Quellenverzeichnis rendern.
|
||||||
*/
|
*/
|
||||||
|
/**
|
||||||
|
* Extrahiert die ZUSAMMENFASSUNG-Sektion aus einem Research-Briefing.
|
||||||
|
* Returns: { zusammenfassung: string|null, remaining: string }
|
||||||
|
*/
|
||||||
|
extractZusammenfassung(summary) {
|
||||||
|
if (!summary) return { zusammenfassung: null, remaining: summary };
|
||||||
|
const pattern = /## ZUSAMMENFASSUNG\s*\n(.*?)(?=\n## |$)/s;
|
||||||
|
const match = summary.match(pattern);
|
||||||
|
if (!match) return { zusammenfassung: null, remaining: summary };
|
||||||
|
const zusammenfassung = match[1].trim();
|
||||||
|
const remaining = summary.substring(0, match.index) + summary.substring(match.index + match[0].length);
|
||||||
|
return { zusammenfassung, remaining: remaining.trim() };
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Rendert die Zusammenfassung als HTML (Bullet Points).
|
||||||
|
*/
|
||||||
|
renderZusammenfassung(text) {
|
||||||
|
if (!text) return '<span style="color:var(--text-disabled);">Noch keine Zusammenfassung.</span>';
|
||||||
|
let html = this.escape(text);
|
||||||
|
// Bullet points
|
||||||
|
html = html.replace(/^- (.+)$/gm, '<li>$1</li>');
|
||||||
|
html = html.replace(/(<li>.*<\/li>\n?)+/gs, '<ul style="margin:4px 0 4px 18px;line-height:1.7;">$&</ul>');
|
||||||
|
// Zeilenumbrueche
|
||||||
|
html = html.replace(/\n(?!<)/g, '<br>');
|
||||||
|
html = html.replace(/(<br>){2,}/g, '<br>');
|
||||||
|
return html;
|
||||||
|
},
|
||||||
|
|
||||||
renderSummary(summary, sourcesJson, incidentType) {
|
renderSummary(summary, sourcesJson, incidentType) {
|
||||||
if (!summary) return '<span style="color:var(--text-tertiary);">Noch keine Zusammenfassung.</span>';
|
if (!summary) return '<span style="color:var(--text-tertiary);">Noch keine Zusammenfassung.</span>';
|
||||||
|
|
||||||
|
|||||||
In neuem Issue referenzieren
Einen Benutzer sperren