fix: brainstorm infinite loop, ghost cursor, embedding ::vector cast, semantic search, billing stats, usage meter accordion
All checks were successful
Deploy to Production / Build and Deploy (push) Successful in 5s
All checks were successful
Deploy to Production / Build and Deploy (push) Successful in 5s
- 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
This commit is contained in:
121
docs/guide-utilisateur/capture-screenshots.mjs
Normal file
121
docs/guide-utilisateur/capture-screenshots.mjs
Normal file
@@ -0,0 +1,121 @@
|
||||
#!/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)
|
||||
Reference in New Issue
Block a user