-
Kacheln fuer den Export auswaehlen:
-
diff --git a/src/static/js/api.js b/src/static/js/api.js
index ab10125..d4f834a 100644
--- a/src/static/js/api.js
+++ b/src/static/js/api.js
@@ -228,9 +228,9 @@ const API = {
resetTutorialState() {
return this._request('DELETE', '/tutorial/state');
},
- exportIncident(id, format, scope) {
+ exportReport(id, format, scope, classification) {
const token = localStorage.getItem('osint_token');
- return fetch(`${this.baseUrl}/incidents/${id}/export?format=${format}&scope=${scope}`, {
+ return fetch(`${this.baseUrl}/incidents/${id}/export?format=${format}&scope=${scope}&classification=${classification}`, {
headers: { 'Authorization': `Bearer ${token}` },
});
},
diff --git a/src/static/js/app.js b/src/static/js/app.js
index 3fc38f8..f588529 100644
--- a/src/static/js/app.js
+++ b/src/static/js/app.js
@@ -772,7 +772,6 @@ const App = {
if (_cardTitle) { _cardTitle.textContent = _lbLabel; _cardTitle.setAttribute("onclick", "openContentModal('" + _lbLabel + "', 'summary-content')"); }
const _toggleBtn = document.querySelector('.layout-toggle-btn[data-tile="lagebild"]');
if (_toggleBtn) _toggleBtn.textContent = _lbLabel;
- const _pdfLabel = document.querySelector('#pdf-export-tiles input[value="lagebild"] + span');
if (_pdfLabel) _pdfLabel.textContent = _lbLabel;
{ const _nt = document.querySelector("#inc-notify-summary"); if (_nt) { const _ns = _nt.closest("label")?.querySelector(".toggle-text"); if (_ns) _ns.textContent = "Neues " + _lbLabel; } }
@@ -2133,252 +2132,31 @@ const App = {
// === Export ===
- toggleExportDropdown(event) {
- event.stopPropagation();
- const menu = document.getElementById('export-dropdown-menu');
- if (!menu) return;
- const isOpen = menu.classList.toggle('show');
- const btn = menu.previousElementSibling;
- if (btn) btn.setAttribute('aria-expanded', String(isOpen));
- },
-
- _closeExportDropdown() {
- const menu = document.getElementById('export-dropdown-menu');
- if (menu) {
- menu.classList.remove('show');
- const btn = menu.previousElementSibling;
- if (btn) btn.setAttribute('aria-expanded', 'false');
- }
- },
-
- openPdfExportDialog() {
- this._closeExportDropdown();
+ openExportModal() {
if (!this.currentIncidentId) return;
- openModal('modal-pdf-export');
+ openModal('modal-export');
},
- executePdfExport() {
- closeModal('modal-pdf-export');
- const checked = [...document.querySelectorAll('#pdf-export-tiles input:checked')].map(c => c.value);
- if (!checked.length) { UI.showToast('Keine Kacheln ausgewählt', 'warning'); return; }
- this._generatePdf(checked);
- },
-
- _generatePdf(tiles) {
- const title = document.getElementById('incident-title')?.textContent || 'Export';
- const now = new Date().toLocaleString('de-DE', { day: '2-digit', month: '2-digit', year: 'numeric', hour: '2-digit', minute: '2-digit' });
-
- let sections = '';
- const esc = (s) => s ? s.replace(/&/g,'&').replace(//g,'>').replace(/"/g,'"') : '';
-
- // === Lagebild ===
- if (tiles.includes('lagebild')) {
- const summaryEl = document.getElementById('summary-text');
- const timestamp = document.getElementById('lagebild-timestamp')?.textContent || '';
- if (summaryEl && summaryEl.innerHTML.trim()) {
- // Clone innerHTML and make citation links clickable with full URL visible
- let summaryHtml = summaryEl.innerHTML;
- // Ensure citation links are styled for print (underlined, blue)
- summaryHtml = summaryHtml.replace(/
]*class="citation"[^>]*>(\[[^\]]+\])<\/a>/g,
- '$2');
- sections += '
'
- + '
' + (this._currentIncidentType === 'research' ? 'Recherchebericht' : 'Lagebild') + '
'
- + (timestamp ? '
' + esc(timestamp) + '
' : '')
- + '
' + summaryHtml + '
'
- + '
';
- }
- }
-
- // === Quellen ===
- if (tiles.includes('quellen')) {
- const articles = this._currentArticles || [];
- if (articles.length) {
- const sourceMap = {};
- articles.forEach(a => {
- const name = a.source || 'Unbekannt';
- if (!sourceMap[name]) sourceMap[name] = [];
- sourceMap[name].push(a);
- });
- const sources = Object.entries(sourceMap).sort((a,b) => b[1].length - a[1].length);
- let s = '
' + articles.length + ' Artikel aus ' + sources.length + ' Quellen
';
- s += '
| Quelle | Artikel | Sprache |
';
- sources.forEach(([name, arts]) => {
- const langs = [...new Set(arts.map(a => (a.language || 'de').toUpperCase()))].join(', ');
- s += '| ' + esc(name) + ' | ' + arts.length + ' | ' + langs + ' |
';
- });
- s += '
';
- s += '
';
- sources.forEach(([name, arts]) => {
- s += '
' + esc(name) + ' (' + arts.length + ')
';
- arts.forEach(a => {
- const hl = esc(a.headline_de || a.headline || 'Ohne Titel');
- const url = a.source_url || '';
- const dateStr = a.published_at ? new Date(a.published_at).toLocaleDateString('de-DE') : '';
- s += '
';
- s += url ? '
' + hl + '' : '
' + hl + '';
- if (dateStr) s += '
(' + dateStr + ')';
- s += '
';
- });
- });
- s += '
';
- sections += '
Quellenübersicht
' + s + '';
- }
- }
-
- // === Faktencheck ===
- if (tiles.includes('faktencheck')) {
- const fcItems = document.querySelectorAll('#factcheck-list .factcheck-item');
- if (fcItems.length) {
- let s = '
';
- fcItems.forEach(item => {
- const status = item.dataset.fcStatus || '';
- const statusEl = item.querySelector('.fc-status-text, .factcheck-status');
- const claimEl = item.querySelector('.fc-claim-text, .factcheck-claim');
- const evidenceEls = item.querySelectorAll('.fc-evidence-chip, .evidence-chip');
- const statusText = statusEl ? statusEl.textContent.trim() : status;
- const claim = claimEl ? claimEl.textContent.trim() : '';
- const statusClass = (status.includes('confirmed') || status.includes('verified')) ? 'confirmed'
- : (status.includes('refuted') || status.includes('disputed')) ? 'refuted'
- : 'unverified';
- s += '
'
- + '
' + esc(statusText) + ''
- + '
' + esc(claim) + '
';
- if (evidenceEls.length) {
- s += '
';
- evidenceEls.forEach(ev => {
- const link = ev.closest('a');
- const href = link ? link.href : '';
- const text = ev.textContent.trim();
- s += href
- ? '
' + esc(text) + ' '
- : '
' + esc(text) + ' ';
- });
- s += '
';
- }
- s += '
';
- });
- s += '
';
- sections += '
Faktencheck
' + s + '';
- }
- }
-
- // === Timeline ===
- if (tiles.includes('timeline')) {
- const buckets = document.querySelectorAll('#timeline .ht-bucket');
- if (buckets.length) {
- let s = '
';
- buckets.forEach(bucket => {
- const label = bucket.querySelector('.ht-bucket-label');
- const items = bucket.querySelectorAll('.ht-item');
- if (label) s += '
' + esc(label.textContent.trim()) + '
';
- items.forEach(item => {
- const time = item.querySelector('.ht-item-time');
- const ttl = item.querySelector('.ht-item-title');
- const src = item.querySelector('.ht-item-source');
- s += '
';
- if (time) s += '' + esc(time.textContent.trim()) + ' ';
- if (ttl) s += '' + esc(ttl.textContent.trim()) + '';
- if (src) s += ' ' + esc(src.textContent.trim()) + '';
- s += '
';
- });
- });
- s += '
';
- sections += '
Ereignis-Timeline
' + s + '';
- }
- }
-
- if (!sections) { UI.showToast('Keine Inhalte zum Exportieren', 'warning'); return; }
-
- const css = `
-@page { margin: 18mm 15mm 18mm 15mm; size: A4; }
-* { box-sizing: border-box; margin: 0; padding: 0; }
-body { font-family: -apple-system, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif; font-size: 11pt; line-height: 1.55; color: #1a1a1a; background: #fff; padding: 0; }
-a { color: #1a5276; }
-
-/* Header: compact, inline with content */
-.pdf-header { border-bottom: 2px solid #2c3e50; padding-bottom: 10px; margin-bottom: 16px; }
-.pdf-header h1 { font-size: 18pt; font-weight: 700; color: #2c3e50; margin-bottom: 2px; }
-.pdf-header .pdf-subtitle { font-size: 9pt; color: #666; }
-
-/* Sections */
-.pdf-section { margin-bottom: 22px; }
-.pdf-section h2 { font-size: 13pt; font-weight: 600; color: #2c3e50; border-bottom: 1px solid #ccc; padding-bottom: 4px; margin-bottom: 10px; }
-.pdf-section h4 { font-size: 10pt; font-weight: 600; color: #444; margin: 10px 0 3px; }
-.pdf-meta { font-size: 9pt; color: #888; margin-bottom: 8px; }
-
-/* Lagebild content */
-.pdf-content { font-size: 10.5pt; line-height: 1.6; }
-.pdf-content h3 { font-size: 11.5pt; font-weight: 600; color: #2c3e50; margin: 12px 0 5px; }
-.pdf-content strong { font-weight: 600; }
-.pdf-content ul { margin: 4px 0 4px 18px; }
-.pdf-content li { margin-bottom: 2px; }
-.pdf-content a, .pdf-content .citation { color: #1a5276; font-weight: 600; text-decoration: underline; cursor: pointer; }
-
-/* Quellen table */
-.pdf-table { width: 100%; border-collapse: collapse; font-size: 9.5pt; margin-bottom: 14px; }
-.pdf-table th { background: #f0f0f0; text-align: left; padding: 5px 8px; border: 1px solid #ddd; font-weight: 600; font-size: 8.5pt; text-transform: uppercase; color: #555; }
-.pdf-table td { padding: 4px 8px; border: 1px solid #ddd; }
-.pdf-table tr:nth-child(even) { background: #fafafa; }
-.pdf-article-list { font-size: 9.5pt; }
-.pdf-article-item { padding: 1px 0; break-inside: avoid; }
-.pdf-article-item a { color: #1a5276; text-decoration: none; }
-.pdf-article-item a:hover { text-decoration: underline; }
-.pdf-date { color: #888; font-size: 8.5pt; }
-
-/* Faktencheck */
-.pdf-fc-list { display: flex; flex-direction: column; gap: 10px; }
-.pdf-fc-item { border: 1px solid #ddd; border-radius: 4px; padding: 8px 12px; break-inside: avoid; }
-.pdf-fc-badge { display: inline-block; font-size: 7.5pt; font-weight: 700; text-transform: uppercase; letter-spacing: 0.4px; padding: 1px 7px; border-radius: 3px; margin-bottom: 3px; }
-.pdf-fc-confirmed { background: #d4edda; color: #155724; }
-.pdf-fc-refuted { background: #f8d7da; color: #721c24; }
-.pdf-fc-unverified { background: #fff3cd; color: #856404; }
-.pdf-fc-claim { font-size: 10.5pt; margin-top: 3px; }
-.pdf-fc-evidence { margin-top: 5px; font-size: 8.5pt; }
-.pdf-fc-ev-link { color: #1a5276; text-decoration: underline; margin-right: 5px; }
-.pdf-fc-ev-tag { background: #eee; padding: 1px 5px; border-radius: 3px; margin-right: 3px; }
-
-/* Timeline */
-.pdf-timeline h4 { color: #2c3e50; border-bottom: 1px solid #eee; padding-bottom: 2px; margin-top: 8px; }
-.pdf-tl-item { padding: 1px 0; font-size: 9.5pt; break-inside: avoid; }
-.pdf-tl-time { color: #888; font-size: 8.5pt; min-width: 36px; display: inline-block; }
-.pdf-tl-source { color: #888; font-size: 8.5pt; }
-
-/* Footer */
-.pdf-footer { margin-top: 24px; padding-top: 8px; border-top: 1px solid #ddd; font-size: 8pt; color: #999; text-align: center; }
-`;
-
- const printHtml = '\n\n\n
\n'
- + '
' + esc(title) + ' \u2014 AegisSight Export\n'
- + '\n'
- + '\n\n'
- + '\n'
- + sections + '\n'
- + '\n'
- + '';
-
- const printWin = window.open('', '_blank', 'width=800,height=600');
- if (!printWin) { UI.showToast('Popup blockiert \u2014 bitte Popup-Blocker deaktivieren', 'error'); return; }
- printWin.document.write(printHtml);
- printWin.document.close();
- printWin.onload = function() { printWin.focus(); printWin.print(); };
- setTimeout(function() { try { printWin.focus(); printWin.print(); } catch(e) {} }, 500);
- },
-
- async exportIncident(format, scope) {
- this._closeExportDropdown();
+ async submitExport() {
if (!this.currentIncidentId) return;
+ const scope = document.querySelector('input[name="export-scope"]:checked').value;
+ const format = document.querySelector('input[name="export-format"]:checked').value;
+ const classification = document.getElementById('export-classification').value;
+
+ const btn = document.getElementById('export-submit-btn');
+ const origText = btn.textContent;
+ btn.disabled = true;
+ btn.textContent = scope === 'summary' ? 'KI generiert Executive Summary...' : 'Wird erstellt...';
+
try {
- const response = await API.exportIncident(this.currentIncidentId, format, scope);
+ const response = await API.exportReport(this.currentIncidentId, format, scope, classification);
if (!response.ok) {
const err = await response.json().catch(() => ({}));
throw new Error(err.detail || 'Fehler ' + response.status);
}
const blob = await response.blob();
const disposition = response.headers.get('Content-Disposition') || '';
- let filename = 'export.' + format;
+ let filename = 'bericht.' + format;
const match = disposition.match(/filename="?([^"]+)"?/);
if (match) filename = match[1];
const url = URL.createObjectURL(blob);
@@ -2389,14 +2167,16 @@ a { color: #1a5276; }
a.click();
document.body.removeChild(a);
URL.revokeObjectURL(url);
- UI.showToast('Export heruntergeladen', 'success');
+ closeModal('modal-export');
+ UI.showToast('Bericht heruntergeladen', 'success');
} catch (err) {
UI.showToast('Export fehlgeschlagen: ' + err.message, 'error');
+ } finally {
+ btn.disabled = false;
+ btn.textContent = origText;
}
},
-
-
// === Sidebar-Stats ===
async updateSidebarStats() {
@@ -3464,11 +3244,7 @@ document.addEventListener('keydown', (e) => {
NotificationCenter.close();
return;
}
- const exportMenu = document.getElementById('export-dropdown-menu');
- if (exportMenu && exportMenu.classList.contains('show')) {
- App._closeExportDropdown();
- return;
- }
+
const fcMenu = document.querySelector('.fc-dropdown-menu.open');
if (fcMenu) {
fcMenu.classList.remove('open');
@@ -3518,8 +3294,6 @@ document.addEventListener('click', (e) => {
// App starten
document.addEventListener('click', (e) => {
- if (!e.target.closest('.export-dropdown')) {
- App._closeExportDropdown();
- }
+
});
document.addEventListener('DOMContentLoaded', () => App.init());