feat(ms-ai-architect): release v1.9.0 with playground v3 + screenshot suite
Version bump: v1.8.0 -> v1.9.0 (minor — plugin API surface unchanged).
Version sync:
- .claude-plugin/plugin.json (canonical), README.md badge,
CHANGELOG.md (full v1.9.0 entry with playground v3 architecture,
validation suite, A11Y artifacts, SemVer rationale),
marketplace root README.md listing.
Screenshot suite (new):
- scripts/screenshots/capture-playground.py — Playwright Python automation
that opens playground from file://, populates __store with Statens vegvesen
ANPR demo data, navigates each surface, paste-imports fixtures, scrolls to
the relevant report-slot, and saves viewport screenshots.
- 6 PNG screenshots in playground/screenshots/ covering: onboarding (18/18
filled), home (3 projects), catalog (24 commands across 5 expansion groups),
classify pyramid (high-risk Annex III), ROS 5x5 matrix + 7-dim radar,
cost P10/P50/P90 distribution.
Doc updates (3 levels per repo policy):
- Plugin README: new "Screenshots" subsection embeds all 6 with description
columns, plus reproduce command.
- Plugin CLAUDE.md: new "Screenshot-suite (v1.9.0)" subsection documenting
the automation, demo-state seeding, and re-run trigger conditions.
- Marketplace root README: ms-ai-architect listing now mentions the
screenshot suite + reproduce command.
Reproduce screenshots: python3 scripts/screenshots/capture-playground.py.
Notes:
- Light-mode tokens are not in the vendored design-system yet. The toggle
swaps data-theme + label correctly (Step 13 mechanics intact), but the
CSS palette only ships dark. Captured dark-mode only; light-mode capture
re-enables when shared/playground-design-system gains [data-theme="light"]
overrides.
- Local CSS fix in playground HTML: added `[hidden] { display: none !important; }`
in the inline app-shell <style> block. The vendored .error-summary rule
sets display: flex which overrode HTML's [hidden] default, leaking the
onboarding error banner on cold start. Plugin-local for now; a proper
fix belongs in shared/playground-design-system/components-tier3.css.
Verified post-bump:
- bash tests/validate-plugin.sh -> 215/215 PASS
- bash tests/run-e2e.sh --playground -> 240/240 PASS
This commit is contained in:
parent
2ad02ed002
commit
9664bf1b1c
13 changed files with 435 additions and 4 deletions
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "ms-ai-architect",
|
||||
"version": "1.8.0",
|
||||
"version": "1.9.0",
|
||||
"description": "Microsoft AI Solution Architect - structured architecture guidance for the full Microsoft AI stack",
|
||||
"author": {
|
||||
"name": "Kjell Tore Guttormsen"
|
||||
|
|
|
|||
|
|
@ -5,6 +5,52 @@ All notable changes to this project will be documented in this file.
|
|||
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
|
||||
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
||||
|
||||
## [1.9.0] - 2026-05-03
|
||||
|
||||
### Added — Playground v3 (full architecture rewrite)
|
||||
|
||||
The playground at `playground/ms-ai-architect-playground.html` was rebuilt from scratch as a multi-surface decision-builder + report viewer (3867 lines, single-file). It replaces the v2 5-step pipeline with a project-aware app that persists state across sessions and visualizes parsed reports inline.
|
||||
|
||||
- **4 surfaces:**
|
||||
- Onboarding — 5 grouped expansion sections (organization, technology, security, architecture, business) with 18 fields covering organization profile, tech stack, compliance, architecture preferences, and business references. Drives prefill across all 24 commands.
|
||||
- Home — 3 entry tracks (Onboard / New project / Catalog) plus project list with completion-meter per project.
|
||||
- Catalog — 24 commands grouped in 5 expansion categories (regulatory, security, economy, documentation, tool) with full-text search, filtered counts, and direct form-launch.
|
||||
- Project — per-project tabs (one per command category), command form prefilled from shared onboarding state, paste-back markdown import that parses and visualizes reports inline.
|
||||
- **Persistent state:** IndexedDB primary store with localStorage fallback. Schema-versioned (`STATE_KEY = 'ms-ai-architect-state-v1'`) with eager `MIGRATIONS` pipeline that runs at cold-load and import time. Throttled writer prevents excessive disk traffic.
|
||||
- **17 inline report renderers** routed via canonical archetype-routing table:
|
||||
- Regulatory (6): classify pyramid, requirements list, transparency text, FRIA, conformity checklist, DPIA matrix-risk-6×5
|
||||
- Security (3): security 5×5 matrix, ROS 5×5 matrix with 7-dimension threat library, review findings
|
||||
- Economy (2): cost distribution P10/P50/P90, license capability matrix
|
||||
- Documentation (6): migrate phased plan, ADR, summary markdown, POC verdict, utredning, compare
|
||||
- **14 markdown parsers** with the same archetype keys, exposed as `window.__PARSERS`. All parsers return `{ok, data}` or `{ok, errors[]}` — never throw.
|
||||
- **Light/dark theme toggle** in the topbar, persisted in `localStorage('ms-ai-architect-theme')`. FOUC-safe: a small bootstrap script in `<head>` reads the saved value before stylesheets parse.
|
||||
- **Export/import** as JSON Decision Record envelope (Blob + FileReader). Schema-version-aware on import; downgrades trigger MIGRATIONS automatically.
|
||||
- **Vendored design-system** at `playground/vendor/playground-design-system/`, kept in sync via `scripts/sync-design-system.mjs ms-ai-architect` from the marketplace root. SHA-256 MANIFEST detects local drift.
|
||||
- **24 ACTIONS** registered through a single delegated click handler on `document` — keeps event-handler footprint minimal.
|
||||
|
||||
### Added — Playground validation
|
||||
|
||||
- `tests/test-playground-v3.sh` — bash 3.2-compatible static structure tests (170 PASS lines): vendored CSS link order, file://-safety, surfaces, 24 commands, 14 parsers, 17 renderers, design-system class usage, exposed globals, 23 ACTIONS handlers.
|
||||
- `tests/test-playground-parsers.sh` — 70 PASS lines: validates 17 fixtures × parser routing keys + handlePasteImport wiring.
|
||||
- `tests/run-e2e.sh --playground` — new flag dispatching both suites; included in `--all`.
|
||||
- `playground/test-fixtures/` — 17 synthetic markdown fixtures (one per report-producing command, ANPR traffic-analysis example) covering all canonical parser archetypes.
|
||||
- `playground/A11Y-RAPPORT.md` — accessibility report skeleton with WCAG 2.2 AA test grid for both themes.
|
||||
- `playground/MANUAL-CHECKLIST.md` — 10-section manual QA checklist (round-trip, schema migration, project CRUD, command form prefill, paste-import per report type, parse errors, export/import cycle, theme toggle, file://-standalone, axe-core a11y per surface) with concrete DevTools-console assertions.
|
||||
|
||||
### Changed
|
||||
|
||||
- `playground/ms-ai-architect-playground.html` — replaced (v2 1990 lines → v3 3867 lines). Same canonical filename, so external links continue to resolve.
|
||||
- Plugin README — new "## Playground (v3)" section documenting the 4-surface architecture and validation matrix.
|
||||
- Plugin CLAUDE.md — replaced v2 5-step pipeline section with v3 architecture overview. `docs/playground-v2-spec.md` retained as historical reference but no longer the contract; v3 spec lives at `.claude/projects/2026-05-03-playground-v3-architecture/`.
|
||||
- Marketplace root README — playground listing for ms-ai-architect updated to describe v3 architecture, persistence model, 17 renderers, theme toggle, and 240-test validation.
|
||||
|
||||
### Notes
|
||||
|
||||
- **Plugin API surface unchanged.** All 24 commands, 12 agents, 5 skills (387 reference docs), 2 hooks, and MCP server configuration remain identical to v1.8.0. Playground v3 is an additive, optional UI surface — users invoking `/architect:*` directly see no behavioral difference.
|
||||
- v1.9.0 is a minor bump per SemVer because the plugin contract (commands/agents/skills/hooks/MCP) is backward-compatible. The playground's local IndexedDB state schema would only affect users who had the v2 playground running; existing state is auto-migrated by the eager MIGRATIONS pipeline.
|
||||
|
||||
---
|
||||
|
||||
## [1.8.0] - 2026-04-09
|
||||
|
||||
### Added
|
||||
|
|
|
|||
|
|
@ -193,6 +193,12 @@ Interaktiv decision-builder + rapport-viewer for Microsoft AI-beslutninger. Erst
|
|||
| Manuell A11Y QA | Se `playground/MANUAL-CHECKLIST.md` | 10 seksjoner inkl. axe-core-kjøring per surface |
|
||||
| A11Y-rapport | `playground/A11Y-RAPPORT.md` | Skjelett — fylles ut etter kjøring |
|
||||
|
||||
### Screenshot-suite (v1.9.0)
|
||||
|
||||
`scripts/screenshots/capture-playground.py` automatiserer screenshots av alle 4 surfaces + 3 rapport-arketyper via Playwright. Output går til `playground/screenshots/` og embeddes i plugin README. Krever Playwright Python-pakke + chromium. Kjøres med `python3 scripts/screenshots/capture-playground.py` — ca. 15-20 sekunder. Demo-state seedes inline (Statens vegvesen ANPR-eksempel matcher fixture-filene), så ingen interaktivt brukerflow er nødvendig.
|
||||
|
||||
Kjør på nytt etter design-endringer i playground eller `shared/playground-design-system/` (etter sync).
|
||||
|
||||
### Vendored design-system
|
||||
|
||||
Playground laster CSS fra `playground/vendor/playground-design-system/` — en vendored
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@
|
|||
|
||||
*AI-generated: all code produced by Claude Code through dialog-driven development. [Full disclosure →](../../README.md#ai-generated-code-disclosure)*
|
||||
|
||||

|
||||

|
||||

|
||||

|
||||

|
||||
|
|
@ -356,7 +356,7 @@ Interactive **decision-builder + report viewer** for Microsoft AI architecture d
|
|||
- **4 surfaces:** Onboarding (18 shared fields) → Home (project list + 3 entry tracks) → Catalog (24 commands grouped by 5 expansion categories with search) → Project (per-project tabs, command form prefill, paste-back report import + visualization)
|
||||
- **Persistent state:** IndexedDB primary store with localStorage fallback. Schema-versioned (`STATE_KEY = 'ms-ai-architect-state-v1'`) with eager `MIGRATIONS` pipeline.
|
||||
- **17 report renderers:** Each report-producing command has a parser (markdown → structured) and renderer (structured → HTML visualization: pyramid, matrix, radar, findings, distribution, capability-matrix, etc.) wired through a canonical archetype-routing table.
|
||||
- **Theme:** Dark default + light mode toggle, persisted in `localStorage('ms-ai-architect-theme')`.
|
||||
- **Theme:** Dark default + light mode toggle, persisted in `localStorage('ms-ai-architect-theme')`. Light-mode tokens are pending in the shared design-system; the toggle works but currently only swaps the label.
|
||||
- **Export/import:** JSON Decision Record envelope (Blob + FileReader), schema-version-aware on import.
|
||||
|
||||
```bash
|
||||
|
|
@ -364,6 +364,19 @@ Interactive **decision-builder + report viewer** for Microsoft AI architecture d
|
|||
open plugins/ms-ai-architect/playground/ms-ai-architect-playground.html
|
||||
```
|
||||
|
||||
### Screenshots
|
||||
|
||||
| Surface | Preview | What you see |
|
||||
|---------|---------|--------------|
|
||||
| Onboarding (18 shared fields, 5 grouped expansions) |  | Sidebar with form-progress per group · all 5 groups collapsed when complete · "Lagre og fortsett" enabled when 18/18 filled |
|
||||
| Home (project list + 3 entry tracks) |  | Greeting based on shared state · 3 entry-track cards · project cards with completion meter (0/17 reports) · sticky topbar with theme toggle |
|
||||
| Catalog (24 commands across 5 expansion categories, full-text search) |  | Search input · 24 of 24 hits · expansion groups (Regulatorisk/Sikkerhet/Økonomi/Dokumentasjon/Verktøy) · expanded card with `RAPPORT` pill, description, argument hints, and "Åpne skjema" |
|
||||
| Project — EU AI Act classify report (pyramid renderer) |  | 4-tier risk pyramid with active tier (`aria-current="true"`) · role + justification · obligations bullet list per Art. 9-49 |
|
||||
| Project — ROS analysis (5×5 matrix + 7-dimension radar) |  | 5×5 risk matrix · color-banded cells with threat-bubbles per consequence × likelihood · radar overlay covering 7 ROS-AI dimensions (Etterlevelse/Konfidensialitet/Integritet/Sporbarhet/Pålitelighet/Robusthet) |
|
||||
| Project — Cost report (P10/P50/P90 distribution) |  | P10/P50/P90 bars · per-component NOK breakdown table · 3-year capex/opex/total/akkumulert ledger |
|
||||
|
||||
Reproduce: `python3 scripts/screenshots/capture-playground.py` (Playwright + chromium required).
|
||||
|
||||
### Validation
|
||||
|
||||
| Test | Command | Coverage |
|
||||
|
|
|
|||
|
|
@ -36,6 +36,11 @@
|
|||
Kompakt med vilje — ingen komponent-CSS skal duplikeres her. -->
|
||||
<style>
|
||||
main#app { min-height: 100vh; padding: 0; }
|
||||
|
||||
/* Hidden-attribute respekt. Vendored .error-summary, .modal-backdrop osv.
|
||||
setter eksplisitt display, som overstyrer HTMLs default [hidden] {display:none}.
|
||||
Globalt override slik at hidden-attributt faktisk skjuler elementet. */
|
||||
[hidden] { display: none !important; }
|
||||
.app-shell { max-width: 1200px; margin: 0 auto; padding: var(--space-6) var(--space-5); }
|
||||
.app-shell--wide { max-width: 1400px; }
|
||||
|
||||
|
|
|
|||
BIN
plugins/ms-ai-architect/playground/screenshots/01-onboarding.png
Normal file
BIN
plugins/ms-ai-architect/playground/screenshots/01-onboarding.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 88 KiB |
BIN
plugins/ms-ai-architect/playground/screenshots/02-home.png
Normal file
BIN
plugins/ms-ai-architect/playground/screenshots/02-home.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 90 KiB |
BIN
plugins/ms-ai-architect/playground/screenshots/03-catalog.png
Normal file
BIN
plugins/ms-ai-architect/playground/screenshots/03-catalog.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 117 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 132 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 45 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 124 KiB |
|
|
@ -0,0 +1,360 @@
|
|||
#!/usr/bin/env python3
|
||||
"""
|
||||
capture-playground.py — Tar screenshots av Playground v3 i alle 4 surfaces × 2 themes.
|
||||
|
||||
Bruker Playwright Python (sync API). Åpner playground/ms-ai-architect-playground.html
|
||||
direkte fra disk via file:// URL og populerer state programmatisk via window.__store
|
||||
før hvert screenshot. Dette gir reproduserbare screenshots uten å klikke gjennom hele
|
||||
brukerflyten manuelt.
|
||||
|
||||
Output: playground/screenshots/*.png
|
||||
|
||||
Kjøring:
|
||||
python3 scripts/screenshots/capture-playground.py
|
||||
|
||||
Krav: Playwright + chromium installert. På macOS:
|
||||
pip3 install playwright
|
||||
playwright install chromium
|
||||
"""
|
||||
|
||||
import json
|
||||
import sys
|
||||
from pathlib import Path
|
||||
from playwright.sync_api import sync_playwright, Page
|
||||
|
||||
PLUGIN_ROOT = Path(__file__).resolve().parent.parent.parent
|
||||
HTML_PATH = PLUGIN_ROOT / "playground" / "ms-ai-architect-playground.html"
|
||||
FIXTURES_DIR = PLUGIN_ROOT / "playground" / "test-fixtures"
|
||||
SCREENSHOTS_DIR = PLUGIN_ROOT / "playground" / "screenshots"
|
||||
|
||||
VIEWPORT = {"width": 1440, "height": 900}
|
||||
TALL_VIEWPORT = {"width": 1440, "height": 1200} # for surfaces med mer innhold
|
||||
|
||||
# Demo-data — Statens vegvesen ANPR-eksempelet (matcher fixtures).
|
||||
DEMO_SHARED = {
|
||||
"organization": {
|
||||
"name": "Statens vegvesen",
|
||||
"description": "Trafikketat ansvarlig for vegnett, kjøretøy og sjåføropplæring",
|
||||
"sector": "Statlig",
|
||||
"size": "2000-10000",
|
||||
"regulatory_requirements": [
|
||||
"Personopplysningsloven/GDPR",
|
||||
"Sikkerhetsloven",
|
||||
"Forvaltningsloven",
|
||||
"Offentleglova",
|
||||
],
|
||||
},
|
||||
"technology": {
|
||||
"cloud_platform": ["Azure", "M365"],
|
||||
"license_type": "E5",
|
||||
"ai_services_in_use": ["Azure OpenAI", "Copilot for M365", "Azure AI Search"],
|
||||
},
|
||||
"security": {
|
||||
"data_classification": ["Intern", "Fortrolig"],
|
||||
"data_residency": "Norge",
|
||||
"dpia_practice": "Systematisk",
|
||||
"certifications": "ISO 27001, ISO/IEC 42001 (under etablering)",
|
||||
},
|
||||
"architecture": {
|
||||
"preferred_platform": "Azure AI Foundry",
|
||||
"integration_needs": ["M365", "SharePoint", "Fagsystemer", "REST API-er"],
|
||||
"annual_ai_budget": "2M-10M",
|
||||
},
|
||||
"business": {
|
||||
"governance_model": "Sentralisert",
|
||||
"doc_format_preferences": ["Markdown", "SharePoint Wiki"],
|
||||
"reference_architecture": "TOGAF + intern AI-styringsmodell",
|
||||
},
|
||||
}
|
||||
|
||||
DEMO_PROJECTS = [
|
||||
{
|
||||
"id": "proj-anpr-2026",
|
||||
"name": "ANPR Trafikkanalyse",
|
||||
"description": "Automatisk skiltgjenkjenning for trafikkflyt-analyse på E18.",
|
||||
"createdAt": "2026-04-15T09:00:00Z",
|
||||
"local": {
|
||||
"system_name": "ANPR Trafikkanalyse",
|
||||
"system_description": "Sanntids skiltgjenkjenning av kjøretøy på utvalgte strekninger på E18 for trafikkflyt-analyse.",
|
||||
"interaction_type": "automatisering",
|
||||
"users": "Vegtrafikkavdelingen + analytikere",
|
||||
"risk_level_assumption": "Høy",
|
||||
"risk_classification": "Høy",
|
||||
"org_role": "Provider",
|
||||
"data_sources": "Kameraer langs E18, kjøretøyregisteret (begrenset), værdata fra met.no",
|
||||
},
|
||||
"reports": {},
|
||||
},
|
||||
{
|
||||
"id": "proj-saksbehandler-2026",
|
||||
"name": "Saksbehandlerassistent",
|
||||
"description": "Copilot-basert assistent for førerkortssøknader og kjøretøy-registrering.",
|
||||
"createdAt": "2026-04-22T10:30:00Z",
|
||||
"local": {
|
||||
"system_name": "Saksbehandlerassistent v1",
|
||||
"system_description": "M365 Copilot Studio-agent som hjelper saksbehandlere med førerkort-søknader, henter relevant lovverk og foreslår sakssvar.",
|
||||
"interaction_type": "beslutningsstøtte",
|
||||
"users": "Saksbehandlere ved 22 trafikkstasjoner",
|
||||
"risk_level_assumption": "Begrenset",
|
||||
"risk_classification": "Begrenset",
|
||||
"org_role": "Deployer",
|
||||
},
|
||||
"reports": {},
|
||||
},
|
||||
{
|
||||
"id": "proj-chatbot-2026",
|
||||
"name": "Brukerstøtte chatbot",
|
||||
"description": "Publikumsrettet chatbot på vegvesen.no for førerkort- og kjøretøyspørsmål.",
|
||||
"createdAt": "2026-05-01T13:15:00Z",
|
||||
"local": {},
|
||||
"reports": {},
|
||||
},
|
||||
]
|
||||
|
||||
|
||||
def read_fixture(name: str) -> str:
|
||||
"""Les en av de 17 ANPR-fixture-filene."""
|
||||
return (FIXTURES_DIR / f"{name}.md").read_text(encoding="utf-8")
|
||||
|
||||
|
||||
def seed_state(page: Page, *, projects=True):
|
||||
"""Populerer __store.state med demo-data og trigger render."""
|
||||
payload = {
|
||||
"shared": DEMO_SHARED,
|
||||
"projects": DEMO_PROJECTS if projects else [],
|
||||
}
|
||||
page.evaluate(
|
||||
"""({shared, projects}) => {
|
||||
for (const k of Object.keys(shared)) {
|
||||
const target = window.__store.state.shared[k];
|
||||
for (const f of Object.keys(shared[k])) target[f] = shared[k][f];
|
||||
}
|
||||
if (projects.length > 0) {
|
||||
window.__store.state.projects.length = 0;
|
||||
for (const p of projects) window.__store.state.projects.push(p);
|
||||
}
|
||||
window.__scheduleRender();
|
||||
}""",
|
||||
payload,
|
||||
)
|
||||
page.wait_for_timeout(200)
|
||||
|
||||
|
||||
def import_reports(page: Page, project_id: str, command_ids: list):
|
||||
"""Kaller __handlePasteImport på et aktivt prosjekt etter at project-surface
|
||||
er rendret. Må kalles ETTER navigate('project') siden handlePasteImport
|
||||
rendrer direkte til DOM-slottet og scheduleRender ville slette det."""
|
||||
page.evaluate(
|
||||
"""({pid}) => { window.__store.state.activeProjectId = pid; }""",
|
||||
{"pid": project_id},
|
||||
)
|
||||
for cmd in command_ids:
|
||||
markdown = read_fixture(cmd)
|
||||
page.evaluate(
|
||||
"""({cmd, md}) => { window.__handlePasteImport(cmd, md); }""",
|
||||
{"cmd": cmd, "md": markdown},
|
||||
)
|
||||
page.wait_for_timeout(150)
|
||||
|
||||
|
||||
def navigate(page: Page, surface: str, project_id: str = None, project_tab: str = None):
|
||||
"""Bytter aktiv surface (og evt. aktivt prosjekt + tab) og trigger render."""
|
||||
page.evaluate(
|
||||
"""({surface, pid}) => {
|
||||
if (pid) window.__store.state.activeProjectId = pid;
|
||||
window.__navigate(surface);
|
||||
}""",
|
||||
{"surface": surface, "pid": project_id},
|
||||
)
|
||||
page.wait_for_timeout(250)
|
||||
# Project-tab er module-local (currentProjectTab) — må klikkes via faktisk knapp
|
||||
if surface == "project" and project_tab:
|
||||
page.evaluate(
|
||||
"""(tab) => {
|
||||
const btn = document.querySelector('[data-action=\"project-tab\"][data-tab=\"' + tab + '\"]');
|
||||
if (btn) btn.click();
|
||||
}""",
|
||||
project_tab,
|
||||
)
|
||||
page.wait_for_timeout(200)
|
||||
|
||||
|
||||
def set_theme(page: Page, theme: str):
|
||||
"""Setter tema (light/dark) før screenshot."""
|
||||
page.evaluate(
|
||||
"""(theme) => {
|
||||
document.documentElement.setAttribute('data-theme', theme);
|
||||
try { localStorage.setItem('ms-ai-architect-theme', theme); } catch(e){}
|
||||
// Re-render topbar slik at theme-toggle-label oppdateres
|
||||
const labels = document.querySelectorAll('[data-theme-label]');
|
||||
for (const l of labels) l.textContent = theme === 'dark' ? 'Mørk' : 'Lys';
|
||||
}""",
|
||||
theme,
|
||||
)
|
||||
page.wait_for_timeout(100)
|
||||
|
||||
|
||||
def shoot(page: Page, name: str, *, full_page: bool = False, scroll_to: str = None):
|
||||
"""Lagrer en screenshot. Default: viewport-only.
|
||||
|
||||
full_page=True: hele scroll-høyden
|
||||
scroll_to: CSS-selektor som scrolles inn i view før shot
|
||||
"""
|
||||
out = SCREENSHOTS_DIR / f"{name}.png"
|
||||
if scroll_to:
|
||||
page.evaluate(
|
||||
"""(sel) => {
|
||||
const el = document.querySelector(sel);
|
||||
if (el) el.scrollIntoView({block: 'start', behavior: 'instant'});
|
||||
window.scrollBy(0, -20);
|
||||
}""",
|
||||
scroll_to,
|
||||
)
|
||||
page.wait_for_timeout(120)
|
||||
page.screenshot(path=str(out), full_page=full_page)
|
||||
print(f" [{name}.png] {out.relative_to(PLUGIN_ROOT)}")
|
||||
|
||||
|
||||
def open_clean(browser, viewport=None):
|
||||
"""Åpner playground med ren state og venter på bootstrap."""
|
||||
context = browser.new_context(viewport=viewport or VIEWPORT)
|
||||
page = context.new_page()
|
||||
# Hopp til about:blank først for å rense localStorage/IDB fra forrige
|
||||
# kontekst-kjøring (file:// kan dele storage på samme browser-instans).
|
||||
page.goto("about:blank")
|
||||
page.evaluate(
|
||||
"""async () => {
|
||||
try { localStorage.clear(); } catch(e){}
|
||||
try { sessionStorage.clear(); } catch(e){}
|
||||
if (typeof indexedDB !== 'undefined' && indexedDB.databases) {
|
||||
try {
|
||||
const dbs = await indexedDB.databases();
|
||||
await Promise.all(dbs.map(d => new Promise(r => {
|
||||
const req = indexedDB.deleteDatabase(d.name); req.onsuccess = req.onerror = req.onblocked = r;
|
||||
})));
|
||||
} catch(e){}
|
||||
}
|
||||
}"""
|
||||
)
|
||||
page.goto(f"file://{HTML_PATH}")
|
||||
# Vent til __store er eksponert (bootstrap fullført)
|
||||
page.wait_for_function("() => window.__store && window.__CATALOG", timeout=10_000)
|
||||
# Skjul evt. error-banner som kan dukke opp fra bootstrap-kanter
|
||||
page.evaluate(
|
||||
"""() => {
|
||||
const errs = document.querySelectorAll('[data-onboarding-errors]');
|
||||
for (const e of errs) e.setAttribute('hidden', '');
|
||||
}"""
|
||||
)
|
||||
return context, page
|
||||
|
||||
|
||||
def main():
|
||||
if not HTML_PATH.exists():
|
||||
print(f"FEIL: {HTML_PATH} mangler", file=sys.stderr)
|
||||
sys.exit(1)
|
||||
|
||||
SCREENSHOTS_DIR.mkdir(parents=True, exist_ok=True)
|
||||
print(f"Lagrer screenshots til: {SCREENSHOTS_DIR.relative_to(PLUGIN_ROOT)}")
|
||||
print()
|
||||
|
||||
with sync_playwright() as pw:
|
||||
browser = pw.chromium.launch(headless=True)
|
||||
|
||||
# NB: light-mode tokens er ikke implementert i det vendrede
|
||||
# design-systemet ennå (kun mørk-tema-vars). Theme-toggle bytter
|
||||
# data-theme + label korrekt, men CSS-fargene endres ikke før
|
||||
# tokens.css får [data-theme="light"]-overrides. Vi capture'r kun
|
||||
# mørk-modus for nå. Når light-tokens kommer, endre listen til
|
||||
# ("dark", "light") for å regenerere parsuffix-screenshots.
|
||||
for theme in ("dark",):
|
||||
suffix = "" if theme == "dark" else "-light"
|
||||
print(f"--- Theme: {theme} ---")
|
||||
|
||||
# 1. Onboarding (utfylt) — TALL viewport for å vise sidebar + alle 5 grupper
|
||||
ctx, page = open_clean(browser, viewport=TALL_VIEWPORT)
|
||||
seed_state(page, projects=False)
|
||||
navigate(page, "onboarding")
|
||||
set_theme(page, theme)
|
||||
page.evaluate(
|
||||
"""() => {
|
||||
const errs = document.querySelectorAll('[data-onboarding-errors]');
|
||||
for (const e of errs) e.setAttribute('hidden', '');
|
||||
}"""
|
||||
)
|
||||
page.wait_for_timeout(150)
|
||||
shoot(page, f"01-onboarding{suffix}")
|
||||
ctx.close()
|
||||
|
||||
# 2. Home (med 3 prosjekter)
|
||||
ctx, page = open_clean(browser)
|
||||
seed_state(page)
|
||||
navigate(page, "home")
|
||||
set_theme(page, theme)
|
||||
page.wait_for_timeout(150)
|
||||
shoot(page, f"02-home{suffix}")
|
||||
ctx.close()
|
||||
|
||||
# 3. Catalog (alle grupper synlig) — utvid de første 2 gruppene
|
||||
ctx, page = open_clean(browser)
|
||||
seed_state(page)
|
||||
navigate(page, "catalog")
|
||||
set_theme(page, theme)
|
||||
page.evaluate(
|
||||
"""() => {
|
||||
const exps = document.querySelectorAll('[data-action="catalog-toggle-group"]');
|
||||
// Klikk de 2 første for å utvide
|
||||
for (let i = 0; i < Math.min(2, exps.length); i++) exps[i].click();
|
||||
}"""
|
||||
)
|
||||
page.wait_for_timeout(200)
|
||||
shoot(page, f"03-catalog{suffix}")
|
||||
ctx.close()
|
||||
|
||||
# 4. Project — classify pyramide (scroll til classify report-slot)
|
||||
ctx, page = open_clean(browser)
|
||||
seed_state(page)
|
||||
navigate(page, "project", project_id="proj-anpr-2026", project_tab="regulatory")
|
||||
set_theme(page, theme)
|
||||
import_reports(page, "proj-anpr-2026", ["classify"])
|
||||
shoot(
|
||||
page,
|
||||
f"04-project-classify-pyramide{suffix}",
|
||||
scroll_to='[data-report-slot="classify"]',
|
||||
)
|
||||
ctx.close()
|
||||
|
||||
# 5. Project — ROS matrix
|
||||
ctx, page = open_clean(browser)
|
||||
seed_state(page)
|
||||
navigate(page, "project", project_id="proj-anpr-2026", project_tab="security")
|
||||
set_theme(page, theme)
|
||||
import_reports(page, "proj-anpr-2026", ["ros"])
|
||||
shoot(
|
||||
page,
|
||||
f"05-project-ros-matrix{suffix}",
|
||||
scroll_to='[data-report-slot="ros"]',
|
||||
)
|
||||
ctx.close()
|
||||
|
||||
# 6. Project — Cost distribution
|
||||
ctx, page = open_clean(browser)
|
||||
seed_state(page)
|
||||
navigate(page, "project", project_id="proj-anpr-2026", project_tab="economy")
|
||||
set_theme(page, theme)
|
||||
import_reports(page, "proj-anpr-2026", ["cost"])
|
||||
shoot(
|
||||
page,
|
||||
f"06-project-cost-distribution{suffix}",
|
||||
scroll_to='[data-report-slot="cost"]',
|
||||
)
|
||||
ctx.close()
|
||||
|
||||
browser.close()
|
||||
|
||||
print()
|
||||
print(f"Ferdig. Screenshots i {SCREENSHOTS_DIR.relative_to(PLUGIN_ROOT)}/")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
Loading…
Add table
Add a link
Reference in a new issue