"""Regenerates docs/img/* from a LOCAL demo instance (fictional data). See README.md in this folder.""" import asyncio, io, sys from PIL import Image from playwright.async_api import async_playwright import pathlib OUT=str(pathlib.Path(__file__).resolve().parents[2]/'docs'/'img') B='http://127.0.0.1:8500' H={'Remote-User':'alex.rivera','Remote-Name':'Alex Rivera','Remote-Email':'alex@example.com','Remote-Groups':'admin'} TOP="document.activeElement&&document.activeElement.blur();document.documentElement.style.scrollBehavior='auto';window.scrollTo(0,0)" AV='AR' async def mk(p,theme='dark',w=1440,h=900): b=await p.chromium.launch(); c=await b.new_context(viewport={'width':w,'height':h},extra_http_headers=H) await c.add_init_script(f"try{{localStorage.setItem('lt_theme','{theme}')}}catch(e){{}}") async def av(route): await route.fulfill(status=200,content_type='image/svg+xml',body=AV) await c.route('**/api/avatar*',av) return b,c async def go(pg,path,wait=5500): await pg.goto(B+path); await pg.wait_for_timeout(wait); await pg.evaluate(TOP); await pg.wait_for_timeout(300) async def el(pg,sel,name,idx=0): l=pg.locator(sel).nth(idx); await l.scroll_into_view_if_needed(); await pg.wait_for_timeout(300); await l.screenshot(path=f'{OUT}/{name}.png'); print(name,'ok') async def select_port(pg,sw,idx): await pg.locator(f'[data-action="select-port"][data-switch="{sw}"][data-port-idx="{idx}"]').first.click(); await pg.wait_for_timeout(1200) async def shots(): async with async_playwright() as p: b,c=await mk(p); pg=await c.new_page(); errs=[]; pg.on('pageerror',lambda e:errs.append(str(e)[:100])) await go(pg,'/'); await pg.screenshot(path=f'{OUT}/dashboard.png'); print('dashboard ok') await el(pg,'#topology-diagram','topology') await el(pg,'.lt-section-header >> text=ALERT QUEUE','alerts-tmp') if False else None full=Image.open(io.BytesIO(await pg.screenshot(full_page=True))) # host cards + unifi table via element crops hb=await pg.locator('#hosts-grid, .host-grid, .hosts-grid').first.bounding_box() if await pg.locator('#hosts-grid, .host-grid, .hosts-grid').count() else None if hb: await pg.locator('#hosts-grid, .host-grid, .hosts-grid').first.screenshot(path=f'{OUT}/host-cards.png'); print('host-cards ok') await go(pg,'/links'); await pg.screenshot(path=f'{OUT}/link-debug.png') names=await pg.evaluate("[...document.querySelectorAll('.link-host-name')].map(e=>e.textContent.trim())"); print('hosts',names) for nm,fn in (('large1','link-debug-sfp-warning'),('compute-storage-gpu-01','link-debug-sfp'),('Pro 24 PoE','link-debug-switch')): i=next((k for k,n in enumerate(names) if nm in n),None) if i is not None: await el(pg,'.link-host-panel',fn,i) await go(pg,'/inspector'); await pg.screenshot(path=f'{OUT}/inspector.png') await select_port(pg,'USW-Aggregation',4); await pg.screenshot(path=f'{OUT}/inspector-port.png',full_page=False) await pg.locator('[data-action="run-diagnostic"]').first.click(); await pg.wait_for_timeout(9000) await pg.evaluate("document.getElementById('diag-results')?.scrollIntoView({block:'start'})"); await pg.wait_for_timeout(600) await pg.screenshot(path=f'{OUT}/inspector-diagnostics.png'); print('diagnostics ok') await go(pg,'/suppressions'); await pg.screenshot(path=f'{OUT}/suppressions.png',full_page=True) print('errors',errs[:3]); await b.close() b,c=await mk(p,'light'); pg=await c.new_page(); await go(pg,'/'); await pg.screenshot(path=f'{OUT}/dashboard-light.png'); await b.close() async def gif(): frames=[] async with async_playwright() as p: b,c=await mk(p,'dark',1280,720); pg=await c.new_page() async def snap(n=1,ms=0): if ms: await pg.wait_for_timeout(ms) im=Image.open(io.BytesIO(await pg.screenshot())).convert('RGB').resize((960,540),Image.LANCZOS) for _ in range(n): frames.append(im) await go(pg,'/',5000); await snap(3) await pg.mouse.wheel(0,620); await snap(3,600) await pg.mouse.wheel(0,700); await snap(2,600) await go(pg,'/links',4500); await snap(3) await pg.mouse.wheel(0,500); await snap(2,500) await go(pg,'/inspector',4000); await snap(2) await select_port(pg,'USW-Aggregation',4); await snap(3) await pg.locator('[data-action="run-diagnostic"]').first.click(); await snap(2,1500); await snap(2,7500) await pg.evaluate("document.getElementById('diag-results')?.scrollIntoView({block:'start'})"); await snap(4,600) await go(pg,'/suppressions',4000); await snap(3) await b.close() pal=[f.quantize(colors=96,method=Image.MEDIANCUT,dither=Image.NONE) for f in frames] pal[0].save(f'{OUT}/demo.gif',save_all=True,append_images=pal[1:],duration=1100,loop=0,optimize=True); print('gif',len(frames)) async def main(): if 'gif' not in sys.argv: await shots() if 'shots' not in sys.argv: await gif() asyncio.run(main())