110 lines
3.4 KiB
TypeScript
110 lines
3.4 KiB
TypeScript
|
|
/**
|
||
|
|
* Discovery script — logs in, captures the dashboard, and probes the sidebar
|
||
|
|
* nav to learn the actual URLs of the sections referenced in our docs.
|
||
|
|
*
|
||
|
|
* Not committed for ongoing use; the canonical capture is run.ts.
|
||
|
|
*/
|
||
|
|
import { chromium, type Page } from 'playwright';
|
||
|
|
import { mkdir, writeFile } from 'node:fs/promises';
|
||
|
|
import { resolve, dirname } from 'node:path';
|
||
|
|
import { fileURLToPath } from 'node:url';
|
||
|
|
|
||
|
|
const __dirname = dirname(fileURLToPath(import.meta.url));
|
||
|
|
const OUT_DIR = resolve(__dirname, '../../src/assets/screenshots/whp');
|
||
|
|
|
||
|
|
function need(name: string): string {
|
||
|
|
const v = process.env[name];
|
||
|
|
if (!v) throw new Error(`missing env: ${name}`);
|
||
|
|
return v;
|
||
|
|
}
|
||
|
|
|
||
|
|
const BASE = need('WHP_BASE');
|
||
|
|
const USER = need('WHP_USER');
|
||
|
|
const PASS = need('WHP_PASS');
|
||
|
|
|
||
|
|
async function login(page: Page): Promise<void> {
|
||
|
|
console.log(`navigating ${BASE}/login.php`);
|
||
|
|
await page.goto(`${BASE}/login.php`, { waitUntil: 'domcontentloaded' });
|
||
|
|
console.log(`landed at ${page.url()}`);
|
||
|
|
|
||
|
|
await page.fill('input[name="user"]', USER);
|
||
|
|
await page.fill('input[name="password"]', PASS);
|
||
|
|
await page.click('button[type="submit"]');
|
||
|
|
await page.waitForLoadState('networkidle');
|
||
|
|
console.log(`logged in, now at ${page.url()}`);
|
||
|
|
}
|
||
|
|
|
||
|
|
async function snapshotPage(page: Page, id: string): Promise<void> {
|
||
|
|
await mkdir(OUT_DIR, { recursive: true });
|
||
|
|
const path = resolve(OUT_DIR, `${id}.png`);
|
||
|
|
await page.screenshot({ path, fullPage: false });
|
||
|
|
console.log(`captured ${id} -> ${path}`);
|
||
|
|
}
|
||
|
|
|
||
|
|
async function listNavLinks(page: Page): Promise<{ text: string; href: string | null }[]> {
|
||
|
|
// Use locator API to collect all anchors with hrefs (no string-eval).
|
||
|
|
const anchors = page.locator('a[href]');
|
||
|
|
const count = await anchors.count();
|
||
|
|
const out: { text: string; href: string | null }[] = [];
|
||
|
|
for (let i = 0; i < count && out.length < 120; i++) {
|
||
|
|
const a = anchors.nth(i);
|
||
|
|
const href = await a.getAttribute('href');
|
||
|
|
if (!href || href.startsWith('#')) continue;
|
||
|
|
const text = ((await a.textContent()) ?? '').trim().slice(0, 60);
|
||
|
|
if (!text) continue;
|
||
|
|
out.push({ text, href });
|
||
|
|
}
|
||
|
|
return out;
|
||
|
|
}
|
||
|
|
|
||
|
|
async function probe(page: Page, label: string, hrefHint: string): Promise<string | null> {
|
||
|
|
const link = page.locator(`a[href*="${hrefHint}"]`).first();
|
||
|
|
if ((await link.count()) === 0) {
|
||
|
|
console.log(` NO MATCH for "${label}" (hint=${hrefHint})`);
|
||
|
|
return null;
|
||
|
|
}
|
||
|
|
const href = await link.getAttribute('href');
|
||
|
|
console.log(` ${label}: ${href}`);
|
||
|
|
return href;
|
||
|
|
}
|
||
|
|
|
||
|
|
async function main(): Promise<void> {
|
||
|
|
const browser = await chromium.launch({ headless: true });
|
||
|
|
const ctx = await browser.newContext({
|
||
|
|
ignoreHTTPSErrors: true,
|
||
|
|
viewport: { width: 1440, height: 900 },
|
||
|
|
});
|
||
|
|
const page = await ctx.newPage();
|
||
|
|
|
||
|
|
try {
|
||
|
|
await login(page);
|
||
|
|
await snapshotPage(page, '_discovery-dashboard');
|
||
|
|
|
||
|
|
const navLinks = await listNavLinks(page);
|
||
|
|
await writeFile(
|
||
|
|
resolve(__dirname, '_discovered-nav.json'),
|
||
|
|
JSON.stringify(navLinks, null, 2),
|
||
|
|
);
|
||
|
|
console.log(`wrote ${navLinks.length} nav links to _discovered-nav.json`);
|
||
|
|
|
||
|
|
for (const [label, hint] of [
|
||
|
|
['Domains', 'domain'],
|
||
|
|
['Sites', 'site'],
|
||
|
|
['Email', 'email'],
|
||
|
|
['Backups', 'backup'],
|
||
|
|
['Monitor', 'monitor'],
|
||
|
|
['Resources', 'resource'],
|
||
|
|
['Dashboard', 'dashboard'],
|
||
|
|
] as const) {
|
||
|
|
await probe(page, label, hint);
|
||
|
|
}
|
||
|
|
} finally {
|
||
|
|
await browser.close();
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
main().catch((err) => {
|
||
|
|
console.error(err);
|
||
|
|
process.exit(1);
|
||
|
|
});
|