@@ -2039,7 +2039,7 @@ def render_user_dashboard_html(
20392039 .result-badge.trivy { background: rgba(251,146,60,.15); color: #fdba74; }
20402040 .result-badge.hosts { background: rgba(148,163,184,.15); color: #cbd5e1; }
20412041 /* ── NLQ FAB ── */
2042- .nlq-fab { position: fixed; bottom: 88px; right: 20px; z-index: 999 ; background: linear-gradient(135deg,#1d4ed8,#0ea5e9); color: #fff; border: none; border-radius: 999px; padding: 14px 20px; font-size: 14px; font-weight: 700; box-shadow: 0 6px 24px rgba(14,165,233,.45); cursor: pointer; display: flex; align-items: center; gap: 8px; transition: transform 0.15s, box-shadow 0.15s; }
2042+ .nlq-fab { position: fixed; bottom: 88px; right: 20px; z-index: 1001 ; background: linear-gradient(135deg,#1d4ed8,#0ea5e9); color: #fff; border: none; border-radius: 999px; padding: 14px 20px; font-size: 14px; font-weight: 700; box-shadow: 0 6px 24px rgba(14,165,233,.45); cursor: pointer; display: flex; align-items: center; gap: 8px; transition: transform 0.15s, box-shadow 0.15s; }
20432043 .nlq-fab:hover { transform: translateY(-2px); box-shadow: 0 10px 30px rgba(14,165,233,.55); }
20442044 @media (min-width: 769px) { .nlq-fab { bottom: 32px; } }
20452045 .nlq-dialog { width: min(640px, calc(100vw - 24px)); }
@@ -2650,14 +2650,22 @@ def render_user_dashboard_html(
26502650 }
26512651
26522652 function renderOverview(overview) {
2653+ if (!overview || typeof overview !== 'object') overview = {};
2654+ const o = {
2655+ total_hosts: overview.total_hosts ?? 0, online_hosts: overview.online_hosts ?? 0,
2656+ offline_hosts: overview.offline_hosts ?? 0, unknown_hosts: overview.unknown_hosts ?? 0,
2657+ alerts_24h: overview.alerts_24h ?? 0, critical_vulns: overview.critical_vulns ?? 0,
2658+ high_vulns: overview.high_vulns ?? 0, sources_reporting: overview.sources_reporting ?? 0,
2659+ sources_healthy: overview.sources_healthy ?? 0, ingested_records: overview.ingested_records ?? 0,
2660+ };
26532661 const cards = [
2654- ['total_hosts', overview .total_hosts, `${overview .online_hosts} online / ${overview .unknown_hosts} unknown`],
2655- ['offline_hosts', overview .offline_hosts, '즉시 확인 대상'],
2656- ['alerts_24h', overview .alerts_24h, 'high + critical'],
2657- ['critical_vulns', overview .critical_vulns, `high ${overview .high_vulns}`],
2658- ['sources_reporting', overview .sources_reporting, 'fleet / wazuh / zabbix / trivy / host_log'],
2659- ['sources_healthy', overview .sources_healthy, '최근 sync success 기준'],
2660- ['ingested_records', overview .ingested_records, 'alerts + vulns + queries + observations'],
2662+ ['total_hosts', o .total_hosts, `${o .online_hosts} online / ${o .unknown_hosts} unknown`],
2663+ ['offline_hosts', o .offline_hosts, '즉시 확인 대상'],
2664+ ['alerts_24h', o .alerts_24h, 'high + critical'],
2665+ ['critical_vulns', o .critical_vulns, `high ${o .high_vulns}`],
2666+ ['sources_reporting', o .sources_reporting, 'fleet / wazuh / zabbix / trivy / host_log'],
2667+ ['sources_healthy', o .sources_healthy, '최근 sync success 기준'],
2668+ ['ingested_records', o .ingested_records, 'alerts + vulns + queries + observations'],
26612669 ].filter(([key]) => (userPreferences.cards || {})[key] !== false);
26622670 if (!cards.length) {
26632671 overviewCardsEl.innerHTML = '<div class=\" empty\" >운영자가 공개한 요약 카드가 없습니다.</div>';
@@ -3540,7 +3548,10 @@ def render_user_dashboard_html(
35403548 await loadDashboard();
35413549 }
35423550
3543- initialize();
3551+ initialize().catch(err => {
3552+ console.error('[MORI] initialize error:', err);
3553+ if (dashboardStatusEl) dashboardStatusEl.textContent = `초기화 오류: ${err.message}`;
3554+ });
35443555 </script>
35453556
35463557 <!-- ── NLQ Floating Action Button ───────────────────────────────────── -->
@@ -4430,14 +4441,22 @@ def render_query_console_html(docs_url: str = DOCS_PORTAL_URL) -> str:
44304441 }
44314442
44324443 function renderOverview(overview) {
4444+ if (!overview || typeof overview !== 'object') overview = {};
4445+ const o = {
4446+ total_hosts: overview.total_hosts ?? 0, online_hosts: overview.online_hosts ?? 0,
4447+ offline_hosts: overview.offline_hosts ?? 0, unknown_hosts: overview.unknown_hosts ?? 0,
4448+ alerts_24h: overview.alerts_24h ?? 0, critical_vulns: overview.critical_vulns ?? 0,
4449+ high_vulns: overview.high_vulns ?? 0, sources_reporting: overview.sources_reporting ?? 0,
4450+ sources_healthy: overview.sources_healthy ?? 0, ingested_records: overview.ingested_records ?? 0,
4451+ };
44334452 const cards = [
4434- ['total_hosts', 'Total Hosts', overview .total_hosts, `${overview .online_hosts} online / ${overview .unknown_hosts} unknown`],
4435- ['offline_hosts', 'Offline Hosts', overview .offline_hosts, '즉시 확인 대상'],
4436- ['alerts_24h', 'High Alerts 24h', overview .alerts_24h, 'high + critical'],
4437- ['critical_vulns', 'Critical Vulns', overview .critical_vulns, `high ${overview .high_vulns}`],
4438- ['sources_reporting', 'Sources Reporting', overview .sources_reporting, 'fleet / wazuh / zabbix / trivy / host_log'],
4439- ['sources_healthy', 'Healthy Collectors', overview .sources_healthy, '최근 sync success 기준'],
4440- ['ingested_records', 'Ingested Records', overview .ingested_records, 'alerts + vulns + queries + observations'],
4453+ ['total_hosts', 'Total Hosts', o .total_hosts, `${o .online_hosts} online / ${o .unknown_hosts} unknown`],
4454+ ['offline_hosts', 'Offline Hosts', o .offline_hosts, '즉시 확인 대상'],
4455+ ['alerts_24h', 'High Alerts 24h', o .alerts_24h, 'high + critical'],
4456+ ['critical_vulns', 'Critical Vulns', o .critical_vulns, `high ${o .high_vulns}`],
4457+ ['sources_reporting', 'Sources Reporting', o .sources_reporting, 'fleet / wazuh / zabbix / trivy / host_log'],
4458+ ['sources_healthy', 'Healthy Collectors', o .sources_healthy, '최근 sync success 기준'],
4459+ ['ingested_records', 'Ingested Records', o .ingested_records, 'alerts + vulns + queries + observations'],
44414460 ];
44424461 overviewCardsEl.innerHTML = cards.map(([key, label, value, sub]) => `
44434462 <section class=\" card metric-card\" role=\" button\" tabindex=\" 0\" data-overview-key=\" ${escapeHtml(key)}\" data-overview-label=\" ${escapeHtml(label)}\" >
@@ -5282,7 +5301,10 @@ def render_query_console_html(docs_url: str = DOCS_PORTAL_URL) -> str:
52825301 await loadUserActivityLog();
52835302 }
52845303
5285- initialize();
5304+ initialize().catch(err => {
5305+ console.error('[MORI Admin] initialize error:', err);
5306+ if (dashboardStatusEl) dashboardStatusEl.textContent = `초기화 오류: ${err.message}`;
5307+ });
52865308 </script>
52875309</body>
52885310</html>"""
0 commit comments