Skip to content

Commit f7fa3ed

Browse files
committed
Add Section 4 preview-page figure
Annotated capture of PR #121's preview deploy of the TotalRisk Users Guide v1.1 preface page. Five callouts: top site nav, sidebar with section navigation, breadcrumb showing location in the document, main article body (where the reviewer reads), and the version-1.1 mention in the body that confirms which revision is being previewed. Editable .pptx in planning/assets/figure-pptx/.
1 parent 06f202a commit f7fa3ed

6 files changed

Lines changed: 254 additions & 0 deletions

File tree

planning/assets/captures/preview-page.coords.json

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,42 @@
1313
"y": 208,
1414
"w": 811,
1515
"h": 45
16+
},
17+
"siteHeader": {
18+
"x": 0,
19+
"y": 0,
20+
"w": 0,
21+
"h": 0
22+
},
23+
"sidebar": {
24+
"x": 0,
25+
"y": 0,
26+
"w": 0,
27+
"h": 0
28+
},
29+
"breadcrumb": {
30+
"x": 332,
31+
"y": 92,
32+
"w": 811,
33+
"h": 34
34+
},
35+
"h1": {
36+
"x": 332,
37+
"y": 208,
38+
"w": 811,
39+
"h": 45
40+
},
41+
"article": {
42+
"x": 300,
43+
"y": 76,
44+
"w": 1140,
45+
"h": 665
46+
},
47+
"footer": {
48+
"x": 332,
49+
"y": 562,
50+
"w": 811,
51+
"h": 23
1652
}
1753
}
1854
}
196 KB
Binary file not shown.
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
"""
2+
Annotated "preview page" figure for Section 4 of the reviewer-workflow
3+
chapter — teaches the reviewer "this is what you read."
4+
5+
Source:
6+
planning/assets/captures/preview-page.png (PR #121 preview, TotalRisk
7+
Users Guide v1.1 preface page)
8+
9+
Highlights:
10+
1. Top site chrome — same look-and-feel as the production docs site
11+
2. Sidebar with the document's section navigation
12+
3. Breadcrumb showing where in the document you are
13+
4. Main article body — where you actually read the content
14+
5. The "Version 1.1" mention in the body that confirms you're on the
15+
in-review revision (no DRAFT watermark; watermark suppression on
16+
previews is intentional, see Section 4 prose)
17+
"""
18+
19+
import sys
20+
from pathlib import Path
21+
22+
sys.path.insert(0, str(Path(__file__).resolve().parent))
23+
from annotate_lib import annotate_and_crop # noqa: E402
24+
25+
REPO_ROOT = Path(__file__).resolve().parents[2]
26+
SRC = REPO_ROOT / "planning" / "assets" / "captures" / "preview-page.png"
27+
OUT = REPO_ROOT / "static" / "figures" / "dev" / "reviewer-workflow" / "fig-06-preview-page.png"
28+
PPTX = REPO_ROOT / "planning" / "assets" / "figure-pptx" / "fig-06-preview-page.pptx"
29+
30+
# Use the full captured viewport, slightly cropped to remove margins.
31+
CROP = (0, 0, 1440, 1000)
32+
33+
# Hand-picked from the rendered preview page (probe missed the sidebar
34+
# because of how Docusaurus mounts it).
35+
top_nav = (0, 0, 1440, 62)
36+
sidebar = (5, 80, 290, 595)
37+
breadcrumb = (310, 88, 600, 38)
38+
article_body = (310, 240, 820, 320)
39+
version_mention = (323, 442, 800, 30) # the "Version 1.1 ..." paragraph
40+
41+
callouts = [
42+
(top_nav[0], top_nav[1], top_nav[2], top_nav[3], "bl", 1),
43+
(sidebar[0], sidebar[1], sidebar[2], sidebar[3], "tr", 2),
44+
(breadcrumb[0], breadcrumb[1], breadcrumb[2], breadcrumb[3], "tl", 3),
45+
(article_body[0], article_body[1], article_body[2], article_body[3], "tl", 4),
46+
(version_mention[0], version_mention[1], version_mention[2], version_mention[3], "tr", 5),
47+
]
48+
49+
annotate_and_crop(SRC, callouts, CROP, OUT, pptx_out=PPTX)
Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
// Find coords on the PR #121 preview page for annotation: sidebar nav,
2+
// breadcrumb, preface heading, body content, version indicator (if any).
3+
4+
import { chromium } from 'playwright';
5+
import { readFileSync, writeFileSync } from 'node:fs';
6+
import { resolve } from 'node:path';
7+
8+
const COORDS_FILE = resolve(process.cwd(), 'planning', 'assets', 'captures', 'preview-page.coords.json');
9+
const TARGET = 'https://usace-rmc.github.io/RMC-Software-Documentation-Previews/pr-121/docs/desktop-applications/rmc-totalrisk/users-guide/v1.1/preface/';
10+
11+
const browser = await chromium.launch({ headless: true });
12+
const context = await browser.newContext({ viewport: { width: 1440, height: 1000 } });
13+
const page = await context.newPage();
14+
await page.goto(TARGET, { waitUntil: 'domcontentloaded' });
15+
await page.waitForTimeout(2500);
16+
17+
const info = await page.evaluate(() => {
18+
const r = (el) => { if (!el) return null; const b = el.getBoundingClientRect(); return { x: Math.round(b.x), y: Math.round(b.y), w: Math.round(b.width), h: Math.round(b.height) }; };
19+
// Header nav (USACE site chrome at top)
20+
const siteHeader = document.querySelector('header, .navbar, nav[role="navigation"]');
21+
// Sidebar (left rail with section nav)
22+
const sidebar = document.querySelector('.theme-doc-sidebar-container, aside.theme-doc-sidebar-container, [class*="sidebar"]');
23+
// Breadcrumb
24+
const breadcrumb = document.querySelector('nav.theme-doc-breadcrumbs, [class*="breadcrumb"]');
25+
// Main page heading
26+
const h1 = document.querySelector('h1');
27+
// Body content (markdown wrapper)
28+
const article = document.querySelector('article, main, .theme-doc-markdown, [class*="docItemContainer"]');
29+
// Footer
30+
const footer = document.querySelector('footer');
31+
return {
32+
siteHeader: r(siteHeader),
33+
sidebar: r(sidebar),
34+
breadcrumb: r(breadcrumb),
35+
h1: r(h1),
36+
article: r(article),
37+
footer: r(footer),
38+
pageHeight: document.documentElement.scrollHeight,
39+
pageWidth: document.documentElement.scrollWidth,
40+
};
41+
});
42+
43+
console.log(JSON.stringify(info, null, 2));
44+
45+
const existing = JSON.parse(readFileSync(COORDS_FILE, 'utf8'));
46+
Object.assign(existing.elements, info);
47+
delete existing.elements.pageHeight;
48+
delete existing.elements.pageWidth;
49+
writeFileSync(COORDS_FILE, JSON.stringify(existing, null, 2));
50+
console.log(`merged into ${COORDS_FILE}`);
51+
52+
await browser.close();
Lines changed: 117 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,117 @@
1+
// Submit a Comment-style review on PR #121 (no Approve, no Request changes
2+
// — won't advance the stage label) and capture the resulting post-submit
3+
// states on the Conversation and Files-changed tabs.
4+
//
5+
// Outputs:
6+
// planning/assets/captures/conversation-post-submit.png
7+
// planning/assets/captures/files-changed-post-submit.png
8+
// planning/assets/captures/post-submit.coords.json
9+
//
10+
// The submitted review is clearly marked as a documentation-screenshot
11+
// artifact in the comment body so future viewers of PR #121 don't
12+
// mistake it for a real review.
13+
14+
import { chromium } from 'playwright';
15+
import { existsSync, mkdirSync, writeFileSync } from 'node:fs';
16+
import { resolve } from 'node:path';
17+
18+
const AUTH_FILE = resolve(process.cwd(), '.playwright-auth', 'github.json');
19+
const OUT_DIR = resolve(process.cwd(), 'planning', 'assets', 'captures');
20+
const FILES_URL = 'https://github.com/USACE-RMC/RMC-Software-Documentation/pull/121/files';
21+
const PR_URL = 'https://github.com/USACE-RMC/RMC-Software-Documentation/pull/121';
22+
23+
const REVIEW_BODY = '**[Documentation training sandbox]** This review was submitted programmatically by the figure-capture pipeline to produce screenshots for the Reviewer Workflow chapter. It is not a real review of the PR. Ignore.';
24+
25+
if (!existsSync(AUTH_FILE)) { console.error('Missing auth file.'); process.exit(1); }
26+
mkdirSync(OUT_DIR, { recursive: true });
27+
28+
const browser = await chromium.launch({ headless: true });
29+
const context = await browser.newContext({ storageState: AUTH_FILE, viewport: { width: 1440, height: 900 } });
30+
const page = await context.newPage();
31+
32+
console.log(`→ ${FILES_URL}`);
33+
await page.goto(FILES_URL, { waitUntil: 'domcontentloaded' });
34+
await page.waitForTimeout(2500);
35+
await page.locator('a:has-text("Dismiss"), button:has-text("Dismiss"), button:has-text("Got it")').first().click({ timeout: 1500 }).catch(() => {});
36+
await page.waitForTimeout(500);
37+
38+
// 1. Open the Submit-review dialog
39+
console.log(' opening submit-review dialog...');
40+
await page.locator('button:has-text("Submit review"), button:has-text("Add your review"), button:has-text("Finish your review")').first().click({ timeout: 4000 });
41+
await page.waitForTimeout(1200);
42+
43+
// 2. Fill the comment textarea
44+
console.log(' typing review body...');
45+
const textarea = page.locator('textarea[placeholder*="comment" i], textarea[name*="body" i], textarea').first();
46+
await textarea.fill(REVIEW_BODY, { timeout: 4000 });
47+
await page.waitForTimeout(400);
48+
49+
// 3. Confirm "Comment" radio is selected (it's the default, but be explicit)
50+
const commentRadio = page.locator('input[type="radio"][value="comment" i], input[type="radio"]').first();
51+
const checked = await commentRadio.isChecked().catch(() => true);
52+
if (!checked) await commentRadio.click({ timeout: 2000 }).catch(() => {});
53+
54+
// 4. Click the dialog's Submit button
55+
console.log(' submitting review...');
56+
// The dialog has its own Submit button — find by its position inside the
57+
// overlay rather than the top-right open-dialog button.
58+
await page.locator('div[role="dialog"] button:has-text("Submit review"), .Overlay button:has-text("Submit review")').first().click({ timeout: 5000 }).catch(async () => {
59+
// Fallback — click any Submit review button visible after dialog open
60+
await page.locator('button:has-text("Submit review")').last().click({ timeout: 4000 });
61+
});
62+
63+
// Wait for the dialog to close and the page to refresh state
64+
await page.waitForTimeout(4000);
65+
console.log(' review submitted.');
66+
67+
// 5. Capture Files-changed post-submit state (no "Add your review" anymore)
68+
await page.locator('a:has-text("Dismiss"), button:has-text("Dismiss"), button:has-text("Got it")').first().click({ timeout: 1500 }).catch(() => {});
69+
await page.screenshot({ path: resolve(OUT_DIR, 'files-changed-post-submit.png'), fullPage: false });
70+
console.log(' wrote files-changed-post-submit.png');
71+
72+
// 6. Navigate to Conversation tab to see the review timeline entry
73+
console.log(`→ ${PR_URL}`);
74+
await page.goto(PR_URL, { waitUntil: 'domcontentloaded' });
75+
await page.waitForTimeout(3000);
76+
await page.locator('a:has-text("Dismiss"), button:has-text("Dismiss"), button:has-text("Got it")').first().click({ timeout: 1500 }).catch(() => {});
77+
78+
// Scroll down to find the new review timeline entry
79+
await page.evaluate(() => {
80+
const allText = document.body.innerText;
81+
// Scroll to the bottom so the latest review event is in viewport
82+
window.scrollTo(0, document.documentElement.scrollHeight);
83+
});
84+
await page.waitForTimeout(800);
85+
86+
await page.screenshot({ path: resolve(OUT_DIR, 'conversation-post-submit.png'), fullPage: true });
87+
console.log(' wrote conversation-post-submit.png (full page)');
88+
89+
// 7. Probe for coords of the new review entry
90+
const coords = await page.evaluate(() => {
91+
const r = (el) => { if (!el) return null; const b = el.getBoundingClientRect(); return { x: Math.round(b.x + window.scrollX), y: Math.round(b.y + window.scrollY), w: Math.round(b.width), h: Math.round(b.height) }; };
92+
// Look for "rmctestreviewer reviewed" or "left a review" event in the timeline
93+
let reviewEvent = null;
94+
for (const el of document.querySelectorAll('div, li, article')) {
95+
const t = (el.innerText || '').slice(0, 300);
96+
if (/rmctestreviewer (left a |reviewed|commented)/i.test(t) && el.getBoundingClientRect().height > 40 && el.getBoundingClientRect().height < 800) {
97+
reviewEvent = el;
98+
break;
99+
}
100+
}
101+
// Look for the review summary card with the training-sandbox text
102+
let reviewCard = null;
103+
for (const el of document.querySelectorAll('div, article, [data-testid="comment-body"], .js-comment, .timeline-comment')) {
104+
const t = (el.innerText || '').slice(0, 300);
105+
if (/Documentation training sandbox/i.test(t)) {
106+
reviewCard = el;
107+
break;
108+
}
109+
}
110+
return { reviewEvent: r(reviewEvent), reviewCard: r(reviewCard), pageHeight: document.documentElement.scrollHeight };
111+
});
112+
113+
writeFileSync(resolve(OUT_DIR, 'post-submit.coords.json'), JSON.stringify({ url: PR_URL, capturedAt: new Date().toISOString(), elements: coords }, null, 2));
114+
console.log(` coords: ${JSON.stringify(coords)}`);
115+
116+
await browser.close();
117+
console.log('\nDone.');
175 KB
Loading

0 commit comments

Comments
 (0)