Skip to content

Commit 6225344

Browse files
author
DavidQ
committed
Add Last Generated Image under Paths or IDs control in Preview Generator V2 - PR_26126_021-preview-generator-v2-last-generated-placement
1 parent c78047b commit 6225344

5 files changed

Lines changed: 374 additions & 213 deletions

File tree

docs/dev/codex_commands.md

Lines changed: 35 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,14 @@
1-
# Codex Commands - PR_26126_020-preview-generator-v2-target-source-and-control-placement
1+
# Codex Commands - PR_26126_021-preview-generator-v2-last-generated-placement
22

33
```bash
4-
codex run "Create PR_26126_020-preview-generator-v2-target-source-and-control-placement. Fix Preview Generator V2 UI only. Preserve existing generation behavior. Default Target Source to Games. Generate Preview must be visible but disabled/greyed out until required fields are provided; do not hide it. Move Capture mode into its own accordion/control section above Render Controls with options \"Full Screen (1600x900 HTML Page)\" and \"Canvas Only\". Move Asset folder into its own accordion/control section below Target Source with value \"assets/images\". Left and right columns must continue to use working accordion sections. Do not modify samples. Do not add schema. Produce review artifacts."
4+
codex run "Create PR_26126_021-preview-generator-v2-last-generated-placement. Fix Preview Generator V2 UI only. Preserve existing generation behavior. Under the \"Paths or IDs\" control in the left panel, add a \"Last Generated Image\" section that displays the most recently generated preview. This must update on every Generate Preview action, replace the previous image (no history), and show an empty state before first generate. Keep it within the left panel accordion flow, directly below the Paths or IDs control. Do not move existing controls. Do not modify samples. Do not add schema. Produce review artifacts."
55
```
66

77
## Validation Commands
88

99
```bash
1010
git diff --check -- tools/preview-generator-v2/index.html docs/dev/codex_commands.md docs/dev/commit_comment.txt
11-
git diff --name-only -- samples games start_of_day tools/shared tools/schemas
11+
git diff --cached --name-only -- samples games start_of_day tools/shared tools/schemas
1212
npm run test:workspace-v2
1313
npm run codex:review-artifacts
1414
```
@@ -51,66 +51,57 @@ await page.goto(`${server.baseUrl}/tools/preview-generator-v2/index.html`, { wai
5151
await page.waitForSelector('#shared-theme-header');
5252
await page.waitForFunction(() => Array.from(document.querySelectorAll('.preview-generator-v2 .accordion-v2__header')).every((header) => header.dataset.accordionV2Bound === 'true'));
5353
54-
async function assertAccordion(selector) {
55-
const header = page.locator(`${selector} .accordion-v2__header`).first();
56-
const content = page.locator(`${selector} .accordion-v2__content`).first();
57-
if (await header.count() !== 1) throw new Error(`${selector} missing accordion header`);
58-
if (await content.count() !== 1) throw new Error(`${selector} missing accordion content`);
59-
await header.click();
60-
await page.waitForFunction((target) => document.querySelector(`${target} .accordion-v2__header`)?.getAttribute('aria-expanded') === 'false', selector);
61-
const collapsed = await content.evaluate((node) => ({ hidden: node.hidden, display: getComputedStyle(node).display, height: node.getBoundingClientRect().height }));
62-
if (!collapsed.hidden || collapsed.display !== 'none' || collapsed.height !== 0) throw new Error(`${selector} did not collapse cleanly`);
63-
await header.click();
64-
await page.waitForFunction((target) => document.querySelector(`${target} .accordion-v2__header`)?.getAttribute('aria-expanded') === 'true', selector);
65-
}
54+
const textareaBox = await page.locator('#sampleList').boundingBox();
55+
const lastGeneratedBox = await page.locator('#lastGeneratedImageSection').boundingBox();
56+
if (!textareaBox || !lastGeneratedBox || lastGeneratedBox.y <= textareaBox.y) throw new Error('Last Generated Image should render below Paths or IDs input.');
57+
if (!(await page.locator('#lastGeneratedImageEmpty').isVisible())) throw new Error('Last Generated Image empty state should be visible before first generate.');
58+
if (await page.locator('#lastGeneratedImagePreview').isVisible()) throw new Error('Last Generated Image preview should be hidden before first generate.');
6659
67-
const leftHeaders = await page.locator('.preview-generator-v2__left-accordion .accordion-v2__header').evaluateAll((headers) => headers.map((header) => header.textContent.trim().replace(/\s+/g, ' ')));
68-
const expectedLeftHeaders = ['Repo Destination +', 'Target Source +', 'Asset folder +', 'Capture mode +', 'Render Controls +'];
69-
if (JSON.stringify(leftHeaders) !== JSON.stringify(expectedLeftHeaders)) throw new Error(`Unexpected left accordion order: ${JSON.stringify(leftHeaders)}`);
70-
71-
for (const selector of [
72-
'.preview-generator-v2__left-accordion:nth-of-type(1)',
73-
'.preview-generator-v2__left-accordion:nth-of-type(2)',
74-
'.preview-generator-v2__left-accordion:nth-of-type(3)',
75-
'.preview-generator-v2__left-accordion:nth-of-type(4)',
76-
'.preview-generator-v2__left-accordion:nth-of-type(5)',
77-
'#outputSummary',
78-
'#statusAccordion'
79-
]) {
80-
await assertAccordion(selector);
81-
}
82-
83-
if (!(await page.locator('#targetTypeGames').isChecked())) throw new Error('Games should be the default Target Source.');
84-
if (await page.locator('#targetTypeSamples').isChecked()) throw new Error('Samples should not be default Target Source.');
85-
if ((await page.locator('#assetFolder').inputValue()) !== 'assets/images') throw new Error('Asset folder should remain assets/images.');
86-
if (!(await page.locator('#executeBtn').isVisible())) throw new Error('Generate Preview should be visible before required fields are provided.');
87-
if (!(await page.locator('#executeBtn').isDisabled())) throw new Error('Generate Preview should be disabled before required fields are provided.');
8860
await page.fill('#baseUrl', server.baseUrl);
8961
await page.fill('#waitMs', '3000');
9062
await page.fill('#sampleList', '0107');
9163
await page.check('#forceRewrite');
92-
if (!(await page.locator('#executeBtn').isVisible()) || !(await page.locator('#executeBtn').isDisabled())) throw new Error('Generate Preview should remain visible and disabled until repo folder is selected.');
9364
await page.check('#targetTypeSamples');
9465
await page.click('#pickRepoBtn');
9566
await page.waitForFunction(() => !document.getElementById('executeBtn').disabled);
96-
await page.waitForFunction(() => document.getElementById('writeFolderActualValue').textContent === 'samples\\phase-01\\0107\\assets\\images');
9767
await page.click('#executeBtn');
98-
await page.waitForFunction(() => document.getElementById('log').textContent.includes('===== SUMMARY ====='), null, { timeout: 35000 });
68+
await page.waitForFunction(() => document.getElementById('lastGeneratedImagePreview') && !document.getElementById('lastGeneratedImagePreview').hidden, null, { timeout: 35000 });
69+
if (await page.locator('#lastGeneratedImageEmpty').isVisible()) throw new Error('Last Generated Image empty state should hide after generate.');
70+
const firstSrc = await page.locator('#lastGeneratedImage').getAttribute('src');
71+
const firstMeta = await page.locator('#lastGeneratedImageMeta').innerText();
72+
if (!firstSrc?.startsWith('blob:')) throw new Error(`Last Generated Image should use an object URL, got ${firstSrc}`);
73+
if (!firstMeta.includes('0107')) throw new Error(`Last Generated Image meta should include first generated label, got ${firstMeta}`);
74+
await page.waitForFunction(() => (window.__previewGeneratorV2Writes || []).length === 1);
75+
76+
await page.fill('#sampleList', '0102');
77+
await page.waitForFunction(() => !document.getElementById('executeBtn').disabled);
78+
await page.click('#executeBtn');
79+
await page.waitForFunction((previousSrc) => {
80+
const img = document.getElementById('lastGeneratedImage');
81+
return img && img.getAttribute('src') && img.getAttribute('src') !== previousSrc;
82+
}, firstSrc, { timeout: 35000 });
83+
const secondSrc = await page.locator('#lastGeneratedImage').getAttribute('src');
84+
const secondMeta = await page.locator('#lastGeneratedImageMeta').innerText();
85+
if (!secondSrc?.startsWith('blob:')) throw new Error(`Replacement Last Generated Image should use an object URL, got ${secondSrc}`);
86+
if (secondSrc === firstSrc) throw new Error('Last Generated Image should replace the prior object URL.');
87+
if (!secondMeta.includes('0102')) throw new Error(`Last Generated Image meta should include second generated label, got ${secondMeta}`);
88+
await page.waitForFunction(() => (window.__previewGeneratorV2Writes || []).length === 2);
9989
const writes = await page.evaluate(() => window.__previewGeneratorV2Writes || []);
100-
if (writes.length !== 1) throw new Error(`Expected exactly one preview write, got ${writes.length}`);
101-
if (!writes[0].path.endsWith('samples/phase-01/0107/assets/images/preview.svg')) throw new Error(`Unexpected write path: ${writes[0].path}`);
102-
if (!writes[0].content.includes('<svg')) throw new Error('Generated content is not SVG-like.');
90+
if (!writes[0].path.endsWith('samples/phase-01/0107/assets/images/preview.svg')) throw new Error(`Unexpected first write path: ${writes[0].path}`);
91+
if (!writes[1].path.endsWith('samples/phase-01/0102/assets/images/preview.svg')) throw new Error(`Unexpected second write path: ${writes[1].path}`);
10392
if (errors.length || consoleErrors.length) throw new Error([...errors, ...consoleErrors].join(' | '));
10493
await browser.close();
10594
await server.close();
106-
console.log('preview-generator-v2 target source and control placement smoke valid');
95+
console.log('preview-generator-v2 last generated image placement smoke valid');
10796
'@ | node --input-type=module -
10897
```
10998

11099
## Notes
111100

112-
The targeted Playwright smoke validates default Games target, visible disabled Generate Preview gating, Asset folder and Capture mode section placement, working left/right accordions, and preserved preview generation after switching to Samples.
101+
The targeted Playwright smoke validates the empty state, placement below `Paths or IDs`, first generated preview render, and second Generate Preview replacement without history.
113102

114103
`npm run test:workspace-v2` was attempted, but the script is not defined in this checkout.
115104

116105
Full samples smoke test was skipped because this PR is scoped to Preview Generator V2 UI only.
106+
107+
An unrelated unstaged sample preview SVG change was present before this PR and was left untouched.

docs/dev/commit_comment.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
Place Preview Generator V2 target controls and keep Generate visibly gated - PR_26126_020-preview-generator-v2-target-source-and-control-placement
1+
Add Preview Generator V2 last generated image preview - PR_26126_021-preview-generator-v2-last-generated-placement

docs/dev/reports/codex_changed_files.txt

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,17 @@ M docs/dev/codex_commands.md
33
M docs/dev/commit_comment.txt
44
M docs/dev/reports/codex_changed_files.txt
55
M docs/dev/reports/codex_review.diff
6+
M samples/phase-02/0224/assets/images/preview.svg
7+
M samples/phase-02/0225/assets/images/preview.svg
8+
M samples/phase-02/0226/assets/images/preview.svg
9+
M samples/phase-02/0227/assets/images/preview.svg
610
M tools/preview-generator-v2/index.html
711

8-
# git diff --stat
9-
docs/dev/codex_commands.md | 33 +++++++++++--------
10-
docs/dev/commit_comment.txt | 2 +-
11-
tools/preview-generator-v2/index.html | 60 ++++++++++++++++++++++-------------
12-
3 files changed, 58 insertions(+), 37 deletions(-)
12+
# git diff --cached --stat
13+
docs/dev/codex_commands.md | 79 ++++++++++++++--------------
14+
docs/dev/commit_comment.txt | 2 +-
15+
tools/preview-generator-v2/index.html | 91 ++++++++++++++++++++++++++++++++
16+
3 files changed, 119 insertions(+), 53 deletions(-)
17+
18+
# unstaged sample changes
19+
Unstaged sample preview SVG changes were present in the worktree and were not staged or packaged for this PR.

0 commit comments

Comments
 (0)