docs+portal: add pilot v1 demo pack
This commit is contained in:
@@ -3441,6 +3441,7 @@ fn role_filtered_report(report: Value, role: PortalRole) -> Value {
|
||||
"business_risk",
|
||||
"business_risk_history_summary",
|
||||
"risk_heatmap",
|
||||
"security_events_summary",
|
||||
"workforce",
|
||||
"markdown",
|
||||
] {
|
||||
@@ -10037,6 +10038,27 @@ mod tests {
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn portal_pilot_demo_navigation_is_present() {
|
||||
for marker in [
|
||||
"Pilot v1 demo",
|
||||
"Executive demo",
|
||||
"Manager demo",
|
||||
"Security demo",
|
||||
"Forensics demo",
|
||||
"Admin demo",
|
||||
"data-demo-view-mode=\"executive\"",
|
||||
"data-demo-view-mode=\"security\"",
|
||||
"data-demo-view-mode=\"forensics\"",
|
||||
"data-demo-view-mode=\"admin\"",
|
||||
] {
|
||||
assert!(
|
||||
INDEX_HTML.contains(marker),
|
||||
"demo navigation missing {marker}"
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn api_contract_artifacts_are_valid_and_future_ui_ready() {
|
||||
let openapi: Value =
|
||||
@@ -10134,6 +10156,7 @@ mod tests {
|
||||
let executive = role_filtered_report(report.clone(), PortalRole::Executive);
|
||||
assert!(executive.get("workforce").is_some());
|
||||
assert!(executive.get("executive_dashboard").is_some());
|
||||
assert!(executive.get("security_events_summary").is_some());
|
||||
assert!(executive.get("risk_incident_candidates").is_none());
|
||||
assert!(executive.get("security_correlation").is_none());
|
||||
|
||||
|
||||
@@ -82,13 +82,17 @@ body.security-mode .small-button,
|
||||
body.security-mode a.button,
|
||||
body.security-mode .tab,
|
||||
body.security-mode .nav-link,
|
||||
body.security-mode .view-button,
|
||||
body.security-mode .demo-button,
|
||||
body.security-mode .control-strip select {
|
||||
background: #111827;
|
||||
color: var(--ink);
|
||||
}
|
||||
|
||||
body.security-mode .tab.is-active,
|
||||
body.security-mode .nav-link.is-active {
|
||||
body.security-mode .nav-link.is-active,
|
||||
body.security-mode .view-button.is-active,
|
||||
body.security-mode .demo-button.is-active {
|
||||
background: #0f2a3a;
|
||||
color: var(--link);
|
||||
}
|
||||
@@ -145,14 +149,16 @@ h1 {
|
||||
|
||||
.control-strip,
|
||||
.header-actions,
|
||||
.view-switch {
|
||||
.view-switch,
|
||||
.demo-switch {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
justify-content: flex-end;
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
.view-switch {
|
||||
.view-switch,
|
||||
.demo-switch {
|
||||
align-items: center;
|
||||
padding: 4px;
|
||||
border: 1px solid var(--line);
|
||||
@@ -160,14 +166,16 @@ h1 {
|
||||
background: var(--panel);
|
||||
}
|
||||
|
||||
.view-switch > span {
|
||||
.view-switch > span,
|
||||
.demo-switch > span {
|
||||
padding: 0 6px;
|
||||
color: var(--muted);
|
||||
font-size: 12px;
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
.view-button {
|
||||
.view-button,
|
||||
.demo-button {
|
||||
min-height: 30px;
|
||||
border: 1px solid transparent;
|
||||
border-radius: 6px;
|
||||
@@ -180,18 +188,21 @@ h1 {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.view-button.is-active {
|
||||
.view-button.is-active,
|
||||
.demo-button.is-active {
|
||||
border-color: #1d4ed8;
|
||||
background: #2563eb;
|
||||
color: #ffffff;
|
||||
}
|
||||
|
||||
.view-button:hover {
|
||||
.view-button:hover,
|
||||
.demo-button:hover {
|
||||
color: var(--ink);
|
||||
background: rgba(37, 99, 235, 0.08);
|
||||
}
|
||||
|
||||
.view-button.is-active:hover {
|
||||
.view-button.is-active:hover,
|
||||
.demo-button.is-active:hover {
|
||||
color: #ffffff;
|
||||
background: #1d4ed8;
|
||||
}
|
||||
@@ -1210,10 +1221,13 @@ pre {
|
||||
.topbar-side { justify-items: stretch; min-width: 0; width: 100%; }
|
||||
.control-strip,
|
||||
.header-actions,
|
||||
.view-switch { justify-content: flex-start; }
|
||||
.view-switch,
|
||||
.demo-switch { justify-content: flex-start; }
|
||||
.control-strip label { min-width: 100%; }
|
||||
.view-switch > span { flex-basis: 100%; }
|
||||
.view-button { flex: 1 1 120px; }
|
||||
.view-switch > span,
|
||||
.demo-switch > span { flex-basis: 100%; }
|
||||
.view-button,
|
||||
.demo-button { flex: 1 1 120px; }
|
||||
h1 { font-size: 24px; }
|
||||
.page-head { flex-direction: column; }
|
||||
.period-banner { flex-direction: column; align-items: flex-start; }
|
||||
|
||||
@@ -248,6 +248,9 @@ function updateViewModeButtons() {
|
||||
document.querySelectorAll("[data-view-mode]").forEach(button => {
|
||||
button.classList.toggle("is-active", button.dataset.viewMode === currentViewMode());
|
||||
});
|
||||
document.querySelectorAll("[data-demo-view-mode]").forEach(button => {
|
||||
button.classList.toggle("is-active", button.dataset.demoViewMode === currentViewMode());
|
||||
});
|
||||
}
|
||||
|
||||
function setViewMode(mode) {
|
||||
@@ -2298,9 +2301,7 @@ function renderSecurityEventsSummary(summary, options = {}) {
|
||||
const title = options.compact
|
||||
? "События безопасности"
|
||||
: "События безопасности за 24 часа";
|
||||
const compactStateText = disabled && options.compact
|
||||
? "Детализация скрыта для роли"
|
||||
: stateText;
|
||||
const compactStateText = stateText;
|
||||
const compactModeText = disabled && options.compact
|
||||
? "Без ИБ-детализации"
|
||||
: disabled
|
||||
@@ -3052,6 +3053,10 @@ document.querySelectorAll("[data-view-mode]").forEach(btn => {
|
||||
btn.addEventListener("click", () => setViewMode(btn.dataset.viewMode));
|
||||
});
|
||||
|
||||
document.querySelectorAll("[data-demo-view-mode]").forEach(btn => {
|
||||
btn.addEventListener("click", () => setViewMode(btn.dataset.demoViewMode));
|
||||
});
|
||||
|
||||
document.getElementById("periodFilter")?.addEventListener("change", event => {
|
||||
state.period = periodFromSelectValue(event.target.value);
|
||||
refresh({ stage: "Получение данных за выбранный период" });
|
||||
|
||||
@@ -58,6 +58,14 @@
|
||||
<button class="view-button" data-view-mode="forensics" type="button">Расследования</button>
|
||||
<button class="view-button" data-view-mode="admin" type="button">Админ</button>
|
||||
</div>
|
||||
<div class="demo-switch" aria-label="Pilot v1 demo navigation">
|
||||
<span>Pilot v1 demo</span>
|
||||
<button class="demo-button is-active" data-demo-view-mode="executive" type="button">Executive demo</button>
|
||||
<button class="demo-button" data-demo-view-mode="manager" type="button">Manager demo</button>
|
||||
<button class="demo-button" data-demo-view-mode="security" type="button">Security demo</button>
|
||||
<button class="demo-button" data-demo-view-mode="forensics" type="button">Forensics demo</button>
|
||||
<button class="demo-button" data-demo-view-mode="admin" type="button">Admin demo</button>
|
||||
</div>
|
||||
<div class="header-actions">
|
||||
<button class="small-button primary" data-open-reports="true">Сформировать отчет</button>
|
||||
<button class="small-button" data-export-markdown="true">Текстовый отчет</button>
|
||||
|
||||
Reference in New Issue
Block a user