Files
Momento/docs/guide-utilisateur/capture-screenshots.mjs
Antigravity 8c7ca69640
All checks were successful
Deploy to Production / Build and Deploy (push) Successful in 5s
fix: brainstorm infinite loop, ghost cursor, embedding ::vector cast, semantic search, billing stats, usage meter accordion
- Fix useBrainstormSocket: stable guestId via useRef, remove setState in cleanup
- Fix GhostCursor: direct DOM manipulation via refs, no useState re-renders
- Fix all SQL embedding queries: add ::vector cast on text columns
- Fix embedding truncation to 15000 chars (under 8192 token limit)
- Fix NoteEmbedding INSERT: remove non-existent updatedAt column
- Fix billing page: show all quota stats in grid instead of single metric
- Fix usage meter: accordion expand/collapse, per-feature detail
- Fix semantic search: rebuild 103 note embeddings, ::vector cast on vectorSearch
- Fix brainstorm expand/manual-idea/create: ::vector cast on embedding SQL
2026-05-16 18:50:34 +00:00

122 lines
4.4 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#!/usr/bin/env node
/**
* Capture les captures d'écran pour docs/guide-utilisateur/screenshots/
*
* Pages publiques : sans identifiants.
* App connectée : définir MOMENTO_DOC_EMAIL et MOMENTO_DOC_PASSWORD
*
* Usage (depuis memento-note/ — Playwright est installé là) :
* node ../docs/guide-utilisateur/capture-screenshots.mjs
* MOMENTO_DOC_EMAIL=you@example.com MOMENTO_DOC_PASSWORD=secret node ../docs/guide-utilisateur/capture-screenshots.mjs
*/
import { createRequire } from 'module'
import path from 'path'
import { fileURLToPath } from 'url'
const __dirname = path.dirname(fileURLToPath(import.meta.url))
const appRoot = path.resolve(__dirname, '../../memento-note')
const require = createRequire(path.join(appRoot, 'package.json'))
const { chromium } = require('playwright')
const OUT = path.join(__dirname, 'screenshots')
function resolveBaseUrl() {
if (process.env.MOMENTO_DOC_BASE_URL) return process.env.MOMENTO_DOC_BASE_URL.replace(/\/$/, '')
try {
const envPath = path.join(appRoot, '.env')
const env = require('fs').readFileSync(envPath, 'utf8')
const m = env.match(/^NEXTAUTH_URL=["']?([^"'\n]+)["']?/m)
if (m) return m[1].replace(/\/$/, '')
} catch {
/* ignore */
}
return 'http://localhost:3000'
}
const BASE = resolveBaseUrl()
async function shot(page, url, name, opts = {}) {
await page.goto(url, { waitUntil: 'domcontentloaded', timeout: 60000 })
await page.waitForTimeout(opts.wait ?? 1000)
if (opts.scrollId) {
const el = page.locator(`#${opts.scrollId}`).first()
if (await el.count()) await el.scrollIntoViewIfNeeded()
}
await page.waitForTimeout(400)
await page.screenshot({ path: path.join(OUT, name), fullPage: !!opts.fullPage })
console.log('✓', name)
}
async function loginIfConfigured(page) {
const email = process.env.MOMENTO_DOC_EMAIL
const password = process.env.MOMENTO_DOC_PASSWORD
if (!email || !password) {
console.log(' Connexion ignorée (MOMENTO_DOC_EMAIL / MOMENTO_DOC_PASSWORD non définis)')
return false
}
console.log(` Connexion sur ${BASE}/login`)
await page.goto(`${BASE}/login`, { waitUntil: 'networkidle' })
await page.locator('#email').fill(email)
await page.locator('#password').fill(password)
await page.locator('form button[type="submit"], form button').first().click()
try {
await page.waitForURL((u) => !u.pathname.includes('/login'), { timeout: 20000 })
} catch {
const err = await page.locator('.text-red-500, [class*="error"]').first().textContent().catch(() => '')
console.warn(
`⚠ Connexion échouée (${err || 'timeout'}). Vérifiez MOMENTO_DOC_EMAIL, MOMENTO_DOC_PASSWORD et NEXTAUTH_URL=${BASE}`,
)
return false
}
console.log('✓ Session connectée →', page.url())
return true
}
console.log(` Base URL: ${BASE}`)
const browser = await chromium.launch({ headless: true })
const page = await browser.newPage({ viewport: { width: 1440, height: 900 } })
await page.goto(`${BASE}/`, { waitUntil: 'networkidle' })
for (const [id, name] of [
[null, '01-landing-hero.png'],
['features', '02-landing-features.png'],
['agents', '03-landing-agents.png'],
['brainstorm', '04-landing-brainstorm.png'],
['pricing', '05-landing-pricing.png'],
['tech', '06-landing-byok.png'],
]) {
if (id) await page.goto(`${BASE}/#${id}`, { waitUntil: 'networkidle' })
else await page.evaluate(() => window.scrollTo(0, 0))
await page.waitForTimeout(600)
if (id) {
const el = page.locator(`#${id}`).first()
if (await el.count()) await el.scrollIntoViewIfNeeded()
}
await page.waitForTimeout(400)
await page.screenshot({ path: path.join(OUT, name) })
console.log('✓', name)
}
await shot(page, `${BASE}/login`, '07-login.png')
await shot(page, `${BASE}/register`, '08-register.png')
await shot(page, `${BASE}/forgot-password`, '09-forgot-password.png')
const loggedIn = await loginIfConfigured(page)
if (loggedIn) {
for (const [route, name] of [
['/home', '10-app-home.png'],
['/chat', '11-app-chat.png'],
['/agents', '12-app-agents.png'],
['/brainstorm', '13-app-brainstorm.png'],
['/lab', '14-app-lab.png'],
['/settings/ai', '15-settings-ai.png'],
['/settings/billing', '16-settings-billing.png'],
['/settings/profile', '17-settings-profile.png'],
['/admin', '18-admin-dashboard.png'],
]) {
await shot(page, `${BASE}${route}`, name, { wait: 1500 })
}
}
await browser.close()
console.log('\nCaptures enregistrées dans', OUT)