The homepage showed seven hand-built JSX imitations of the netOrk UI. They are gone; every image is now a screenshot of netOrk v0.28.0 itself, taken from an anonymized copy of a production database (scripts/demo) with scripts/screenshots/capture.py and published as WebP (~630 KB for all eight). - Hero: the device inventory. Walkthrough: device detail, VLANs, the Security tab, the vulnerability triage queue (replacing the config-diff row), the dashboard and service checks (new row 6). NIS2: the audit log, filtered to what people did. - Copy follows the images: row 3 describes the security assessment, row 4 the triage queue; row 2 no longer claims corrections are always automatic; 18 widgets. Alt texts in both languages. - Also fixed on the homepage: the NIS2 teaser for Art. 21 (2e) and the container list of a deployment (three worker pools, plus Flower, registry, APT cache and the Signal gateway). - Demo tooling hardened on the real dump: secrets inside JSON (Wi-Fi keys), reverse DNS zones, glued identifiers, tens of thousands of CrowdSec addresses, a schema newer than the release (anonymize, then downgrade), MFA-enforcing roles, and click steps for view filters. - DESIGN.md: real screenshots only. PAGES.md: the six rows as they are. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
49 lines
1.9 KiB
Python
49 lines
1.9 KiB
Python
"""The screenshots the website uses, as data.
|
|
|
|
Each shot is one page of the netOrk UI. `path` may contain `{placeholders}`
|
|
that are filled from `--var name=value` on the command line (device IDs
|
|
differ per instance, so they are never hard-coded here). Device detail
|
|
sections are addressed through the URL hash the UI itself writes
|
|
(`#security/assessment`, `#config`, ...), so no clicking is needed.
|
|
|
|
`mask` lists extra CSS selectors to cover on top of the automatic masks
|
|
(public IPv4 addresses, e-mail addresses, and the terms from the mask file).
|
|
"""
|
|
|
|
from dataclasses import dataclass, field
|
|
|
|
|
|
@dataclass
|
|
class Shot:
|
|
name: str
|
|
path: str
|
|
# Selector that must be visible before the shot is taken.
|
|
wait_for: str = "main"
|
|
mask: list[str] = field(default_factory=list)
|
|
full_page: bool = False
|
|
# Crop height in CSS pixels; None keeps the viewport height.
|
|
height: int | None = None
|
|
# Width of the published WebP in pixels (the capture is 3200 wide).
|
|
width: int = 1600
|
|
# Selectors clicked in order before the shot, first match each. Only for
|
|
# controls that change the view (filters, tabs); the API guard in
|
|
# capture.py aborts anything that would write.
|
|
clicks: list[str] = field(default_factory=list)
|
|
|
|
|
|
SHOTS: list[Shot] = [
|
|
Shot("devices", "/devices", width=2400),
|
|
Shot("device-detail", "/devices/{ap}#networking/interfaces"),
|
|
Shot("vlans", "/vlans"),
|
|
Shot("device-security", "/devices/{server}#security/assessment"),
|
|
Shot("vulnerabilities", "/vulnerabilities"),
|
|
Shot("dashboard", "/"),
|
|
# Background polls drown out what people did: filter the scheduler out,
|
|
# the way a reader would (click a source badge, then flip it to exclude).
|
|
Shot("audit-log", "/audit-log", clicks=[
|
|
"tbody td >> text=scheduler",
|
|
"button[title='Click to toggle include/exclude']",
|
|
]),
|
|
Shot("service-checks", "/monitoring/checks"),
|
|
]
|