Skip to content

Commit 513746d

Browse files
author
DavidQ
committed
Polish Preview Generator V2 fullscreen header, repo controls, status block, and output summary sizing - PR_26126_014-preview-generator-v2-layout-polish
1 parent ff4c079 commit 513746d

5 files changed

Lines changed: 778 additions & 805 deletions

File tree

docs/dev/codex_commands.md

Lines changed: 32 additions & 154 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
1-
# Codex Commands - PR_26126_013-preview-generator-v2-reskin-fixes
1+
# Codex Commands - PR_26126_014-preview-generator-v2-layout-polish
22

33
```bash
4-
codex run "Create PR_26126_013-preview-generator-v2-reskin-fixes. Fix Preview Generator V2 reskin only. Preserve existing preview.html functionality. Remove all copied preview.html CSS and use only Palette Manager V2-style HTML/classes plus Preview Generator V2 wrapper classes where needed. Move STOP into the Palette Manager-style NAV next to Generate Preview. Fix Repo selected so it populates correctly from the selected repo destination/folder. Remove the Repo Sample control entirely. Populate the write folder sample text as \"samples\\phaseXX\\XXXX\\assets\\images\". Ensure Write folder is populated correctly. Remove the \"Paths or IDs\" label/field wrapper from the center column structure shown in preview-generator-v2__paths-field. Move the existing textarea to the top of the layout/control flow. Do not add JSON UI. Do not create schema. Do not modify samples. Update targeted tests if needed and produce review artifacts."
4+
codex run "Create PR_26126_014-preview-generator-v2-layout-polish. Fix Preview Generator V2 UI polish only. Preserve existing generation behavior. Fix Hide Header & Details so it enters the same fullscreen/collapsed-header behavior used by Palette Manager V2. Move Pick Repo Folder above Repo Selected. Status must not use an accordion; render Status as a normal compact status block. Reduce Output Summary height so it fits content instead of stretching tall; keep Write folder sample and Write folder compact and readable. Do not modify samples. Do not add schema. Produce review artifacts."
55
```
66

77
## Validation Commands
@@ -34,189 +34,67 @@ await page.route('https://cdn.jsdelivr.net/**', async (route) => {
3434
});
3535
await page.addInitScript(() => {
3636
const writes = [];
37-
class FakeFile {
38-
constructor(text) {
39-
this._text = text;
40-
}
41-
async text() {
42-
return this._text;
43-
}
44-
}
37+
class FakeFile { constructor(text) { this._text = text; } async text() { return this._text; } }
4538
class FakeFileHandle {
46-
constructor(path, existing = null) {
47-
this.kind = 'file';
48-
this.name = path.split('/').pop();
49-
this.path = path;
50-
this._existing = existing;
51-
}
52-
async getFile() {
53-
return new FakeFile(this._existing || '');
54-
}
55-
async createWritable() {
56-
const path = this.path;
57-
return {
58-
async write(content) {
59-
writes.push({ path, content: String(content) });
60-
},
61-
async close() {}
62-
};
63-
}
39+
constructor(path, existing = null) { this.kind = 'file'; this.name = path.split('/').pop(); this.path = path; this._existing = existing; }
40+
async getFile() { return new FakeFile(this._existing || ''); }
41+
async createWritable() { const path = this.path; return { async write(content) { writes.push({ path, content: String(content) }); }, async close() {} }; }
6442
}
6543
class FakeDirectoryHandle {
66-
constructor(name = 'SelectedRepoFolder', path = '') {
67-
this.kind = 'directory';
68-
this.name = name;
69-
this.path = path;
70-
this.children = new Map();
71-
}
72-
async getDirectoryHandle(name) {
73-
const key = `dir:${name}`;
74-
if (!this.children.has(key)) {
75-
const nextPath = this.path ? `${this.path}/${name}` : name;
76-
this.children.set(key, new FakeDirectoryHandle(name, nextPath));
77-
}
78-
return this.children.get(key);
79-
}
80-
async getFileHandle(name, options = {}) {
81-
const key = `file:${name}`;
82-
if (!this.children.has(key)) {
83-
if (!options.create) {
84-
throw new DOMException('Not found', 'NotFoundError');
85-
}
86-
const nextPath = this.path ? `${this.path}/${name}` : name;
87-
this.children.set(key, new FakeFileHandle(nextPath));
88-
}
89-
return this.children.get(key);
90-
}
44+
constructor(name = 'SelectedRepoFolder', path = '') { this.kind = 'directory'; this.name = name; this.path = path; this.children = new Map(); }
45+
async getDirectoryHandle(name) { const key = `dir:${name}`; if (!this.children.has(key)) { const nextPath = this.path ? `${this.path}/${name}` : name; this.children.set(key, new FakeDirectoryHandle(name, nextPath)); } return this.children.get(key); }
46+
async getFileHandle(name, options = {}) { const key = `file:${name}`; if (!this.children.has(key)) { if (!options.create) { throw new DOMException('Not found', 'NotFoundError'); } const nextPath = this.path ? `${this.path}/${name}` : name; this.children.set(key, new FakeFileHandle(nextPath)); } return this.children.get(key); }
9147
}
9248
window.__previewGeneratorV2Writes = writes;
9349
window.showDirectoryPicker = async () => new FakeDirectoryHandle();
9450
});
9551
9652
await page.goto(`${server.baseUrl}/tools/preview-generator-v2/index.html`, { waitUntil: 'domcontentloaded' });
9753
await page.waitForSelector('#shared-theme-header');
54+
await page.waitForFunction(() => document.querySelector('[data-preview-generator-v2-summary]')?.dataset.toolsPlatformSummaryActive === '1');
9855
99-
const requiredSelectors = [
100-
'.palette-manager-v2__menu-sample',
101-
'#executeBtn',
102-
'#stopBtn',
103-
'#pickRepoBtn',
104-
'#targetTypeSamples',
105-
'#targetTypeGames',
106-
'#targetTypeTools',
107-
'#baseUrl',
108-
'#waitMs',
109-
'#assetFolder',
110-
'#forceRewrite',
111-
'#onlyCaptureTimeout',
112-
'#captureModeFullScreen',
113-
'#captureModeCanvasOnly',
114-
'#sampleList',
115-
'#repoSelectedValue',
116-
'#writeFolderSampleValue',
117-
'#writeFolderActualValue',
118-
'#status',
119-
'#log',
120-
'#frame'
121-
];
122-
for (const selector of requiredSelectors) {
123-
const locator = page.locator(selector);
124-
if (await locator.count() !== 1) {
125-
throw new Error(`Expected one ${selector}`);
126-
}
127-
}
128-
129-
const menuButtons = await page.locator('.palette-manager-v2__menu-sample button').evaluateAll((buttons) => buttons.map((button) => button.textContent.trim()));
130-
if (JSON.stringify(menuButtons) !== JSON.stringify(['Generate Preview', 'Stop'])) {
131-
throw new Error(`Unexpected menu buttons: ${JSON.stringify(menuButtons)}`);
132-
}
133-
134-
const hasCopiedPreviewCss = await page.locator('link[href*="shared/preview/preview-pages.css"]').count();
135-
if (hasCopiedPreviewCss !== 0) {
136-
throw new Error('Copied preview stylesheet is still loaded.');
137-
}
138-
const copiedClassCounts = await page.evaluate(() => ({
139-
row: document.querySelectorAll('.row').length,
140-
inline: document.querySelectorAll('.inline').length,
141-
inlineLabel: document.querySelectorAll('.inline-label').length,
142-
valueBox: document.querySelectorAll('.value-box').length,
143-
pathsField: document.querySelectorAll('.preview-generator-v2__paths-field').length
144-
}));
145-
for (const [name, count] of Object.entries(copiedClassCounts)) {
146-
if (count !== 0) {
147-
throw new Error(`Copied preview class still present: ${name}=${count}`);
148-
}
149-
}
150-
151-
const forbiddenSelectors = [
152-
'#applyToGameButton',
153-
'#exportImageButton',
154-
'#destinationDataInput',
155-
'textarea[aria-label*="JSON" i]',
156-
'textarea[id*="json" i]',
157-
'pre[id*="json" i]'
158-
];
159-
for (const selector of forbiddenSelectors) {
160-
if (await page.locator(selector).count() !== 0) {
161-
throw new Error(`Forbidden JSON/action UI found: ${selector}`);
162-
}
163-
}
164-
165-
const sectionNames = await page.locator('.accordion-v2__header span:first-child').evaluateAll((items) => items.map((item) => item.textContent.trim()));
166-
for (const expected of ['Repo Destination', 'Target Source', 'Render Controls', 'Output Summary', 'Status']) {
167-
if (!sectionNames.includes(expected)) {
168-
throw new Error(`Missing section: ${expected}`);
169-
}
170-
}
171-
if (sectionNames.includes('Paths or IDs')) {
172-
throw new Error('Paths or IDs accordion header should not exist.');
173-
}
174-
175-
if (await page.locator('label[for="sampleList"]').count() !== 0) {
176-
throw new Error('Paths or IDs field label wrapper should not exist.');
177-
}
56+
const repoOrder = await page.locator('#repoDestinationAccordionContent > *').evaluateAll((nodes) => nodes.map((node) => node.textContent.trim().replace(/\s+/g, ' ')));
57+
if (!repoOrder[0].includes('Pick Repo Folder') || !repoOrder[1].includes('Repo selected')) throw new Error(`Repo destination order is wrong: ${JSON.stringify(repoOrder)}`);
58+
if (await page.locator('#statusAccordionContent').count() !== 0) throw new Error('Status accordion content still exists.');
59+
if (await page.locator('.accordion-v2__header span:text-is("Status")').count() !== 0) throw new Error('Status is still rendered as an accordion header.');
60+
if (await page.locator('.preview-generator-v2__status-block #status').count() !== 1) throw new Error('Status block does not contain status text.');
17861
62+
const outputFlex = await page.locator('.preview-generator-v2__output-summary').evaluate((node) => getComputedStyle(node).flexGrow);
63+
if (outputFlex !== '0') throw new Error(`Output Summary should not flex-grow; got ${outputFlex}`);
17964
const initialSampleText = await page.locator('#writeFolderSampleValue').innerText();
180-
if (initialSampleText !== 'samples\\phaseXX\\XXXX\\assets\\images') {
181-
throw new Error(`Unexpected write-folder sample text: ${initialSampleText}`);
182-
}
65+
if (initialSampleText !== 'samples\\phaseXX\\XXXX\\assets\\images') throw new Error(`Unexpected write-folder sample text: ${initialSampleText}`);
66+
67+
const summary = page.locator('[data-preview-generator-v2-summary]');
68+
await summary.click();
69+
await page.waitForFunction(() => document.querySelector('.is-collapsible')?.open === false);
70+
await page.waitForFunction(() => document.querySelector('[data-preview-generator-v2-summary]')?.dataset.toolsPlatformSummaryState === 'collapsed');
71+
await summary.click();
72+
await page.waitForFunction(() => document.querySelector('.is-collapsible')?.open === true);
18373
18474
await page.fill('#baseUrl', server.baseUrl);
18575
await page.fill('#waitMs', '3000');
18676
await page.fill('#sampleList', '0107');
18777
await page.check('#forceRewrite');
18878
await page.click('#pickRepoBtn');
18979
await page.waitForFunction(() => !document.getElementById('executeBtn').disabled);
190-
const repoSelected = await page.locator('#repoSelectedValue').innerText();
191-
if (repoSelected !== 'SelectedRepoFolder') {
192-
throw new Error(`Repo selected did not populate from folder handle: ${repoSelected}`);
193-
}
19480
await page.waitForFunction(() => document.getElementById('writeFolderActualValue').textContent === 'samples\\phase-01\\0107\\assets\\images');
19581
await page.click('#executeBtn');
19682
await page.waitForFunction(() => document.getElementById('log').textContent.includes('===== SUMMARY ====='), null, { timeout: 35000 });
19783
const writes = await page.evaluate(() => window.__previewGeneratorV2Writes || []);
198-
if (writes.length !== 1) {
199-
throw new Error(`Expected exactly one preview write, got ${writes.length}`);
200-
}
201-
if (!writes[0].path.endsWith('samples/phase-01/0107/assets/images/preview.svg')) {
202-
throw new Error(`Unexpected write path: ${writes[0].path}`);
203-
}
204-
if (!writes[0].content.includes('<svg')) {
205-
throw new Error('Generated content is not SVG-like.');
206-
}
207-
if (errors.length || consoleErrors.length) {
208-
throw new Error([...errors, ...consoleErrors].join(' | '));
209-
}
84+
if (writes.length !== 1) throw new Error(`Expected exactly one preview write, got ${writes.length}`);
85+
if (!writes[0].path.endsWith('samples/phase-01/0107/assets/images/preview.svg')) throw new Error(`Unexpected write path: ${writes[0].path}`);
86+
if (!writes[0].content.includes('<svg')) throw new Error('Generated content is not SVG-like.');
87+
if (errors.length || consoleErrors.length) throw new Error([...errors, ...consoleErrors].join(' | '));
21088
await browser.close();
21189
await server.close();
212-
console.log('preview-generator-v2 reskin fixes browser smoke valid');
90+
console.log('preview-generator-v2 layout polish browser smoke valid');
21391
'@ | node --input-type=module -
21492
```
21593

21694
## Notes
21795

218-
The targeted browser smoke validates the Palette Manager-style reskin fixes, confirms Stop is in the nav, verifies the old copied preview CSS/classes are gone, checks the write-folder text behavior, and exercises the existing preview generation write path.
96+
The targeted Playwright smoke validates the Preview Generator V2 layout polish, including Palette Manager-style collapsed header behavior, Pick Repo order, normal Status block, compact Output Summary sizing, and the existing preview generation write path.
21997

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

222-
Full samples smoke test was skipped because this PR is scoped to Preview Generator V2 only.
100+
Full samples smoke test was skipped because this PR is scoped to Preview Generator V2 UI polish only.

docs/dev/commit_comment.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
Fix Preview Generator V2 reskin without changing generator behavior - PR_26126_013-preview-generator-v2-reskin-fixes
1+
Polish Preview Generator V2 layout and collapsed header behavior - PR_26126_014-preview-generator-v2-layout-polish

docs/dev/reports/codex_changed_files.txt

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ M docs/dev/codex_commands.md
44
M tools/preview-generator-v2/index.html
55

66
# git diff --stat
7-
docs/dev/codex_commands.md | 56 +++--
7+
docs/dev/codex_commands.md | 186 ++++-------------------
88
docs/dev/commit_comment.txt | 2 +-
9-
tools/preview-generator-v2/index.html | 420 +++++++++++++---------------------
10-
3 files changed, 209 insertions(+), 269 deletions(-)
9+
tools/preview-generator-v2/index.html | 271 ++++++++++++++++++++++++++++++----
10+
3 files changed, 279 insertions(+), 180 deletions(-)

0 commit comments

Comments
 (0)