Promote develop → main (2026-07-25 22:22 UTC) #16
@@ -1390,3 +1390,14 @@ details.adv-section .adv-hint { grid-column: 1 / -1; font-size: 12px; color: var
|
|||||||
[data-theme="light"] .audit-entry-detail summary { color: #475569; }
|
[data-theme="light"] .audit-entry-detail summary { color: #475569; }
|
||||||
[data-theme="light"] /* === Verwendungs-Sicht (Phase 6) === */
|
[data-theme="light"] /* === Verwendungs-Sicht (Phase 6) === */
|
||||||
.activity-cell { color: #475569; }
|
.activity-cell { color: #475569; }
|
||||||
|
|
||||||
|
/* === Verlinkte Dashboard-Kacheln und -Karten === */
|
||||||
|
.stat-card-link { cursor: pointer; transition: border-color 0.15s ease, transform 0.15s ease; }
|
||||||
|
.stat-card-link:hover, .stat-card-link:focus-visible {
|
||||||
|
border-color: var(--accent);
|
||||||
|
transform: translateY(-1px);
|
||||||
|
}
|
||||||
|
.card-link { cursor: pointer; transition: border-color 0.15s ease; }
|
||||||
|
.card-link:hover, .card-link:focus-visible { border-color: var(--accent); }
|
||||||
|
.card-link .card-link-chevron { color: var(--text-muted); transition: color 0.15s ease, transform 0.15s ease; }
|
||||||
|
.card-link:hover .card-link-chevron { color: var(--accent); transform: translateX(2px); }
|
||||||
|
|||||||
@@ -6,7 +6,7 @@
|
|||||||
<title>AegisSight Monitor-Verwaltung</title>
|
<title>AegisSight Monitor-Verwaltung</title>
|
||||||
<link rel="icon" type="image/svg+xml" href="/static/favicon.svg">
|
<link rel="icon" type="image/svg+xml" href="/static/favicon.svg">
|
||||||
<link rel="apple-touch-icon" href="/static/favicon.svg">
|
<link rel="apple-touch-icon" href="/static/favicon.svg">
|
||||||
<link rel="stylesheet" href="/static/css/style.css?v=20260725a">
|
<link rel="stylesheet" href="/static/css/style.css?v=20260725b">
|
||||||
<script>(function(){var t=localStorage.getItem('portal_theme');if(t==='light')document.documentElement.setAttribute('data-theme','light');try{var a=JSON.parse(localStorage.getItem('osint_a11y')||'{}');Object.keys(a).forEach(function(k){if(a[k])document.documentElement.setAttribute('data-a11y-'+k,'true');});}catch(e){}})()</script>
|
<script>(function(){var t=localStorage.getItem('portal_theme');if(t==='light')document.documentElement.setAttribute('data-theme','light');try{var a=JSON.parse(localStorage.getItem('osint_a11y')||'{}');Object.keys(a).forEach(function(k){if(a[k])document.documentElement.setAttribute('data-a11y-'+k,'true');});}catch(e){}})()</script>
|
||||||
|
|
||||||
<style>
|
<style>
|
||||||
@@ -70,9 +70,10 @@
|
|||||||
<div class="stats-grid" id="statsGrid"></div>
|
<div class="stats-grid" id="statsGrid"></div>
|
||||||
|
|
||||||
<div style="display: grid; grid-template-columns: 1fr 1fr; gap: 16px;">
|
<div style="display: grid; grid-template-columns: 1fr 1fr; gap: 16px;">
|
||||||
<div class="card">
|
<div class="card card-link" onclick="gotoSection('licenses')" role="link" tabindex="0" title="Zu den Lizenzen">
|
||||||
<div class="card-header">
|
<div class="card-header">
|
||||||
<h2>Bald ablaufende Lizenzen</h2>
|
<h2>Bald ablaufende Lizenzen</h2>
|
||||||
|
<svg class="card-link-chevron" xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><polyline points="9 18 15 12 9 6"/></svg>
|
||||||
</div>
|
</div>
|
||||||
<div class="card-body">
|
<div class="card-body">
|
||||||
<ul class="expiring-list" id="expiringList">
|
<ul class="expiring-list" id="expiringList">
|
||||||
@@ -81,9 +82,10 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="card">
|
<div class="card card-link" onclick="gotoSection('audit')" role="link" tabindex="0" title="Zum Audit-Log">
|
||||||
<div class="card-header">
|
<div class="card-header">
|
||||||
<h2>Letzte Aktivität</h2>
|
<h2>Letzte Aktivität</h2>
|
||||||
|
<svg class="card-link-chevron" xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><polyline points="9 18 15 12 9 6"/></svg>
|
||||||
</div>
|
</div>
|
||||||
<div class="card-body" id="recentActivity">
|
<div class="card-body" id="recentActivity">
|
||||||
<div class="text-muted">Laden...</div>
|
<div class="text-muted">Laden...</div>
|
||||||
@@ -1239,7 +1241,7 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<script src="/static/js/a11y.js?v=20260725a"></script>
|
<script src="/static/js/a11y.js?v=20260725a"></script>
|
||||||
<script src="/static/js/app.js?v=20260725b"></script>
|
<script src="/static/js/app.js?v=20260725c"></script>
|
||||||
<script src="/static/js/sources.js?v=20260522x2"></script>
|
<script src="/static/js/sources.js?v=20260522x2"></script>
|
||||||
<script src="/static/js/x-scraper.js?v=20260522a"></script>
|
<script src="/static/js/x-scraper.js?v=20260522a"></script>
|
||||||
<script src="/static/js/source-health.js?v=20260509l"></script>
|
<script src="/static/js/source-health.js?v=20260509l"></script>
|
||||||
|
|||||||
@@ -75,6 +75,26 @@ function openRechnerTab() {
|
|||||||
if (tab) tab.click();
|
if (tab) tab.click();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Tab-Wechsel per Name, nutzt die vorhandene Nav-Logik
|
||||||
|
function gotoSection(name) {
|
||||||
|
const tab = document.querySelector(`.nav-tab[data-section="${name}"]`);
|
||||||
|
if (tab) tab.click();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Dashboard-Kacheln als Sprungziele verdrahten (Klick + Enter/Leertaste)
|
||||||
|
function wireStatCardLinks() {
|
||||||
|
document.querySelectorAll("#statsGrid .stat-card-link").forEach((card) => {
|
||||||
|
const go = () => {
|
||||||
|
if (card.dataset.href) window.open(card.dataset.href, "_blank", "noopener");
|
||||||
|
else if (card.dataset.goto) gotoSection(card.dataset.goto);
|
||||||
|
};
|
||||||
|
card.addEventListener("click", go);
|
||||||
|
card.addEventListener("keydown", (e) => {
|
||||||
|
if (e.key === "Enter" || e.key === " ") { e.preventDefault(); go(); }
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
// --- State ---
|
// --- State ---
|
||||||
let currentOrgId = null;
|
let currentOrgId = null;
|
||||||
let orgsCache = [];
|
let orgsCache = [];
|
||||||
@@ -147,27 +167,30 @@ async function loadDashboard() {
|
|||||||
try {
|
try {
|
||||||
const stats = await API.get("/api/dashboard/stats");
|
const stats = await API.get("/api/dashboard/stats");
|
||||||
|
|
||||||
|
// Kacheln sind Sprungziele. data-goto wechselt den Tab, data-href oeffnet
|
||||||
|
// extern (Vorfaelle leben im Monitor, nicht im Portal).
|
||||||
document.getElementById("statsGrid").innerHTML = `
|
document.getElementById("statsGrid").innerHTML = `
|
||||||
<div class="stat-card">
|
<div class="stat-card stat-card-link" data-goto="orgs" role="link" tabindex="0" title="Zu den Organisationen">
|
||||||
<div class="stat-label">Organisationen</div>
|
<div class="stat-label">Organisationen</div>
|
||||||
<div class="stat-value">${stats.organizations.total}</div>
|
<div class="stat-value">${stats.organizations.total}</div>
|
||||||
<div class="stat-sub">${stats.organizations.active} aktiv</div>
|
<div class="stat-sub">${stats.organizations.active} aktiv</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="stat-card">
|
<div class="stat-card stat-card-link" data-goto="orgs" role="link" tabindex="0" title="Nutzer werden je Organisation verwaltet">
|
||||||
<div class="stat-label">Nutzer</div>
|
<div class="stat-label">Nutzer</div>
|
||||||
<div class="stat-value">${stats.users.total}</div>
|
<div class="stat-value">${stats.users.total}</div>
|
||||||
<div class="stat-sub">${stats.users.active} aktiv</div>
|
<div class="stat-sub">${stats.users.active} aktiv</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="stat-card">
|
<div class="stat-card stat-card-link" data-goto="licenses" role="link" tabindex="0" title="Zu den Lizenzen">
|
||||||
<div class="stat-label">Aktive Lizenzen</div>
|
<div class="stat-label">Aktive Lizenzen</div>
|
||||||
<div class="stat-value">${stats.licenses.active}</div>
|
<div class="stat-value">${stats.licenses.active}</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="stat-card">
|
<div class="stat-card stat-card-link" data-href="https://monitor.aegis-sight.de" role="link" tabindex="0" title="Vorfälle liegen im Monitor (öffnet neuen Tab)">
|
||||||
<div class="stat-label">Vorfälle</div>
|
<div class="stat-label">Vorfälle</div>
|
||||||
<div class="stat-value">${stats.incidents.total}</div>
|
<div class="stat-value">${stats.incidents.total}</div>
|
||||||
<div class="stat-sub">${stats.incidents.active} aktiv</div>
|
<div class="stat-sub">${stats.incidents.active} aktiv</div>
|
||||||
</div>
|
</div>
|
||||||
`;
|
`;
|
||||||
|
wireStatCardLinks();
|
||||||
|
|
||||||
// Expiring licenses
|
// Expiring licenses
|
||||||
const expList = document.getElementById("expiringList");
|
const expList = document.getElementById("expiringList");
|
||||||
|
|||||||
In neuem Issue referenzieren
Einen Benutzer sperren