Skip to content

Commit 0209d74

Browse files
eprifticlaude
andcommitted
Add comprehensive README with screenshots and Playwright capture script
Rewrite README.md with feature list, architecture diagram, screenshots gallery, full API endpoint reference, results visualization docs, and project structure. Add Playwright-based screenshot automation (docs/capture_screenshots.mjs) that captures 11 pages: landing, login, projects, data, parameters, and all 5 results sub-tabs (summary, best model, population, co-presence, comparative). Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
1 parent 02a8b07 commit 0209d74

13 files changed

+388
-71
lines changed

README.md

Lines changed: 233 additions & 71 deletions
Large diffs are not rendered by default.

docs/capture_screenshots.mjs

Lines changed: 155 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,155 @@
1+
/**
2+
* Capture screenshots of PredomicsApp pages for documentation.
3+
* Usage: node docs/capture_screenshots.mjs
4+
*
5+
* Prerequisites: npm install playwright
6+
* The app must be running at BASE URL (default http://localhost:8001).
7+
*/
8+
import { chromium } from 'playwright';
9+
10+
const BASE = 'http://localhost:8001';
11+
const OUT = 'docs/screenshots';
12+
const CREDS = { email: 'edi.prifti@gmail.com', password: 'editest' };
13+
const PROJECT_ID = 'd0810056bcc1';
14+
const JOB_ID = '4180f1e459ac';
15+
16+
async function dismissOverlays(page) {
17+
await page.evaluate(() => {
18+
document.querySelectorAll('.tour-overlay, .tour-backdrop, [class*="tour"]').forEach(el => el.remove());
19+
localStorage.setItem('tour_completed', 'true');
20+
localStorage.setItem('tourDone', 'true');
21+
localStorage.setItem('predomics_tour_done', 'true');
22+
});
23+
const skipBtn = await page.$('button:has-text("Skip"), button:has-text("Close"), button:has-text("Got it"), .tour-skip');
24+
if (skipBtn) await skipBtn.click({ force: true }).catch(() => {});
25+
await page.waitForTimeout(300);
26+
}
27+
28+
async function main() {
29+
const browser = await chromium.launch();
30+
const ctx = await browser.newContext({
31+
viewport: { width: 1440, height: 900 },
32+
colorScheme: 'dark',
33+
});
34+
const page = await ctx.newPage();
35+
36+
// ── 1. Landing / Home page (unauthenticated) ──
37+
await page.goto(BASE);
38+
await page.waitForTimeout(2000);
39+
await dismissOverlays(page);
40+
await page.screenshot({ path: `${OUT}/01_landing.png` });
41+
console.log('1/11 Landing page ✓');
42+
43+
// ── 2. Login page ──
44+
await page.goto(`${BASE}/login`);
45+
await page.waitForTimeout(1000);
46+
await page.screenshot({ path: `${OUT}/02_login.png` });
47+
console.log('2/11 Login page ✓');
48+
49+
// ── Authenticate via API and inject token into localStorage ──
50+
await page.evaluate(async (creds) => {
51+
const resp = await fetch('/api/auth/login', {
52+
method: 'POST',
53+
headers: { 'Content-Type': 'application/json' },
54+
body: JSON.stringify(creds),
55+
});
56+
if (!resp.ok) throw new Error(`Login failed: ${resp.status}`);
57+
const data = await resp.json();
58+
localStorage.setItem('token', data.access_token);
59+
}, CREDS);
60+
console.log(' Authenticated (token injected)');
61+
62+
// ── 3. Projects page ──
63+
await page.goto(`${BASE}/projects`);
64+
await page.waitForTimeout(3000);
65+
await dismissOverlays(page);
66+
await page.screenshot({ path: `${OUT}/03_projects.png` });
67+
console.log('3/11 Projects list ✓');
68+
69+
// ── 4. Project Data & Run tab ──
70+
await page.goto(`${BASE}/project/${PROJECT_ID}/data`);
71+
await page.waitForTimeout(4000);
72+
await dismissOverlays(page);
73+
await page.screenshot({ path: `${OUT}/04_project_data.png` });
74+
console.log('4/11 Project data tab ✓');
75+
76+
// ── 5. Parameters tab ──
77+
await page.goto(`${BASE}/project/${PROJECT_ID}/parameters`);
78+
await page.waitForTimeout(3000);
79+
await dismissOverlays(page);
80+
await page.screenshot({ path: `${OUT}/05_parameters.png` });
81+
console.log('5/11 Parameters tab ✓');
82+
83+
// ── 6. Results — Summary ──
84+
await page.goto(`${BASE}/project/${PROJECT_ID}/results/${JOB_ID}`);
85+
await page.waitForTimeout(6000);
86+
await dismissOverlays(page);
87+
// Scroll past the jobs table to show the results sub-tab content
88+
await page.evaluate(() => {
89+
const subTabs = document.querySelector('button.active')?.closest('.sub-tabs, [class*="sub"]');
90+
if (subTabs) subTabs.scrollIntoView({ block: 'start' });
91+
else window.scrollBy(0, 600);
92+
});
93+
await page.waitForTimeout(1000);
94+
await page.screenshot({ path: `${OUT}/06_results_summary.png` });
95+
console.log('6/11 Results summary ✓');
96+
97+
// Helper: click a sub-tab and scroll to content area
98+
async function clickSubTab(label) {
99+
await page.evaluate((lbl) => {
100+
const btns = [...document.querySelectorAll('button')];
101+
const btn = btns.find(b => b.textContent.trim() === lbl);
102+
if (btn) {
103+
btn.click();
104+
btn.scrollIntoView({ block: 'start' });
105+
}
106+
}, label);
107+
}
108+
109+
// ── 7. Best Model sub-tab ──
110+
try {
111+
await clickSubTab('Best Model');
112+
await page.waitForTimeout(4000);
113+
await page.evaluate(() => window.scrollBy(0, -60));
114+
await page.screenshot({ path: `${OUT}/07_best_model.png` });
115+
console.log('7/11 Best Model ✓');
116+
} catch { console.log('7/11 Best Model — SKIPPED (no button)'); }
117+
118+
// ── 8. Population sub-tab ──
119+
try {
120+
await clickSubTab('Population');
121+
await page.waitForTimeout(4000);
122+
await page.evaluate(() => window.scrollBy(0, -60));
123+
await page.screenshot({ path: `${OUT}/08_population.png` });
124+
console.log('8/11 Population ✓');
125+
} catch { console.log('8/11 Population — SKIPPED'); }
126+
127+
// ── 9. Co-presence sub-tab ──
128+
try {
129+
await clickSubTab('Co-presence');
130+
await page.waitForTimeout(6000);
131+
await page.evaluate(() => window.scrollBy(0, -60));
132+
await page.screenshot({ path: `${OUT}/09_copresence.png` });
133+
console.log('9/11 Co-presence ✓');
134+
135+
// Scroll to see heatmap + network
136+
await page.evaluate(() => window.scrollBy(0, 900));
137+
await page.waitForTimeout(3000);
138+
await page.screenshot({ path: `${OUT}/10_copresence_network.png` });
139+
console.log('10/11 Co-presence network ✓');
140+
} catch (e) { console.log('9-10/11 Co-presence — SKIPPED:', e.message); }
141+
142+
// ── 11. Comparative sub-tab ──
143+
try {
144+
await clickSubTab('Comparative');
145+
await page.waitForTimeout(4000);
146+
await page.evaluate(() => window.scrollBy(0, -60));
147+
await page.screenshot({ path: `${OUT}/11_comparative.png` });
148+
console.log('11/11 Comparative ✓');
149+
} catch { console.log('11/11 Comparative — SKIPPED'); }
150+
151+
await browser.close();
152+
console.log(`\nDone! Screenshots saved to ${OUT}/`);
153+
}
154+
155+
main().catch(e => { console.error(e); process.exit(1); });

docs/screenshots/01_landing.png

107 KB
Loading

docs/screenshots/02_login.png

33.5 KB
Loading

docs/screenshots/03_projects.png

48.3 KB
Loading
159 KB
Loading

docs/screenshots/05_parameters.png

124 KB
Loading
98.1 KB
Loading

docs/screenshots/07_best_model.png

141 KB
Loading

docs/screenshots/08_population.png

113 KB
Loading

0 commit comments

Comments
 (0)