Skip to content

Commit b90c8f8

Browse files
author
DavidQ
committed
Hydrate manifest repoPath so Preview Generator can enable direct generation - PR_26127_017-repo-path-manifest-hydration-fix
1 parent 12ee16a commit b90c8f8

7 files changed

Lines changed: 85 additions & 17 deletions

File tree

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
# PR_26127_017-repo-path-manifest-hydration-fix
2+
3+
## Summary
4+
- Added forward-slash absolute `repoPath` values to Workspace Manager V2 UAT, Asteroids, Pong, and Gravity Well manifests.
5+
- Kept `repoRoot` as the display-only repo label.
6+
- Preserved optional `repoPath` support in `tools/schemas/workspace.manifest.schema.json`.
7+
- Preview Generator V2 continues to use `repoPath` as the workspace launch direct-write root.
8+
- Preview Generator V2 keeps `Pick Repo Folder` hidden when launched from Workspace Manager V2.
9+
10+
## Manifest Hydration Notes
11+
- `repoPath` uses `C:/Users/davidq/Documents/GitHub/HTML-JavaScript-Gaming`.
12+
- `repoPath` is passed through the Workspace Manager V2 manifest/session launch context.
13+
- Asteroids, Pong, and Gravity Well Preview Generator V2 launches hydrate with:
14+
- absolute `repoPath`
15+
- visible target source limited to games
16+
- manifest preview source
17+
- generated preview target
18+
- enabled Generate Preview
19+
20+
## Direct Write Notes
21+
- Preview Generator V2 combines `repoPath` with the generated preview target for workspace direct writes.
22+
- Missing `repoPath` is still covered as an actionable disabled state.
23+
- `/__workspace-manager-v2/repo-root` is not called.
24+
25+
## Validation
26+
- `npm run test:workspace-v2`
27+
- Result: PASS, 10 tests passed.
28+
- Validated Asteroids direct write to generated preview target and Asteroids/Pong/Gravity Well launch hydration enabling Generate Preview.
29+
30+
## Out Of Scope
31+
- Deprecated `tools/workspace-v2` was not modified.
32+
- Sample JSON was not modified.
33+
- Full samples smoke test was skipped because this PR is repoPath hydration scoped.

games/Asteroids/game.manifest.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
"gameRoot": "games/Asteroids/",
1010
"assetsPath": "games/Asteroids/assets",
1111
"repoRoot": "HTML-JavaScript-Gaming",
12-
"repoPath": "C:\\Users\\davidq\\Documents\\GitHub\\HTML-JavaScript-Gaming",
12+
"repoPath": "C:/Users/davidq/Documents/GitHub/HTML-JavaScript-Gaming",
1313
"tools": {
1414
"palette-manager-v2": {
1515
"$schema": "tools/schemas/tools/palette-manager-v2.schema.json",

games/GravityWell/game.manifest.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
"gameRoot": "games/GravityWell/",
1010
"assetsPath": "games/GravityWell/assets",
1111
"repoRoot": "HTML-JavaScript-Gaming",
12+
"repoPath": "C:/Users/davidq/Documents/GitHub/HTML-JavaScript-Gaming",
1213
"tools": {
1314
"palette-manager-v2": {
1415
"$schema": "tools/schemas/tools/palette-manager-v2.schema.json",

games/_template/workspace-manager-v2-UAT.manifest.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
"gameRoot": "games/_template/",
1010
"assetsPath": "games/_template/assets",
1111
"repoRoot": "HTML-JavaScript-Gaming",
12+
"repoPath": "C:/Users/davidq/Documents/GitHub/HTML-JavaScript-Gaming",
1213
"tools": {
1314
"palette-manager-v2": {
1415
"$schema": "tools/schemas/tools/palette-manager-v2.schema.json",

games/pong/game.manifest.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
"gameRoot": "games/Pong/",
1010
"assetsPath": "games/Pong/assets",
1111
"repoRoot": "HTML-JavaScript-Gaming",
12+
"repoPath": "C:/Users/davidq/Documents/GitHub/HTML-JavaScript-Gaming",
1213
"tools": {
1314
"palette-manager-v2": {
1415
"$schema": "tools/schemas/tools/palette-manager-v2.schema.json",

tests/playwright/tools/WorkspaceManagerV2.spec.mjs

Lines changed: 47 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,10 @@ async function openToolsIndex(page) {
2525
return server;
2626
}
2727

28+
function manifestRepoPath(server) {
29+
return server.repoRoot.replaceAll("\\", "/");
30+
}
31+
2832
test.describe("Workspace Manager V2 bootstrap", () => {
2933
test.afterAll(async () => {
3034
await coverageReporter.writeReport();
@@ -235,7 +239,7 @@ test.describe("Workspace Manager V2 bootstrap", () => {
235239
await expect(page.locator("#workspaceContextOutput")).toHaveValue(/"gameRoot": "games\/Asteroids\/"/);
236240
await expect(page.locator("#workspaceContextOutput")).toHaveValue(/"assetsPath": "games\/Asteroids\/assets"/);
237241
await expect(page.locator("#workspaceContextOutput")).toHaveValue(/"repoRoot": "HTML-JavaScript-Gaming"/);
238-
expect(JSON.parse(await page.locator("#workspaceContextOutput").inputValue()).repoPath).toBe(server.repoRoot);
242+
expect(JSON.parse(await page.locator("#workspaceContextOutput").inputValue()).repoPath).toBe(manifestRepoPath(server));
239243
await expect(page.locator("#workspaceContextOutput")).not.toHaveValue(/"previewImagePath"/);
240244
await expect(page.locator("#workspaceContextOutput")).toHaveValue(/"assets.image.bezel.bezel"/);
241245
await expect(page.locator("#workspaceContextOutput")).toHaveValue(/"assets.image.preview.preview"/);
@@ -313,7 +317,7 @@ test.describe("Workspace Manager V2 bootstrap", () => {
313317
expect(savedManifest.documentKind).toBe("workspace-manifest");
314318
expect(Object.keys(savedManifest.tools).sort()).toEqual(["asset-manager-v2", "palette-manager-v2", "vector-map-editor"]);
315319
expect(savedManifest.repoRoot).toBe("HTML-JavaScript-Gaming");
316-
expect(savedManifest.repoPath).toBe(server.repoRoot);
320+
expect(savedManifest.repoPath).toBe(manifestRepoPath(server));
317321
expect(savedManifest.tools["palette-manager-v2"].swatches.length).toBeGreaterThan(0);
318322
expect(Object.keys(savedManifest.tools["asset-manager-v2"].assets)).toHaveLength(14);
319323
expect(savedManifest.tools["asset-manager-v2"].previewImagePath).toBeUndefined();
@@ -390,7 +394,7 @@ test.describe("Workspace Manager V2 bootstrap", () => {
390394
expect(storedContext.gameRoot).toBe("games/Asteroids/");
391395
expect(storedContext.assetsPath).toBe("games/Asteroids/assets");
392396
expect(storedContext.repoRoot).toBe("HTML-JavaScript-Gaming");
393-
expect(storedContext.repoPath).toBe(server.repoRoot);
397+
expect(storedContext.repoPath).toBe(manifestRepoPath(server));
394398
expect(storedContext.tools["palette-manager-v2"].swatches.length).toBeGreaterThan(0);
395399
expect(Object.keys(storedContext.tools["asset-manager-v2"].assets)).toHaveLength(14);
396400
expect(storedContext.tools["asset-manager-v2"].previewImagePath).toBeUndefined();
@@ -526,7 +530,7 @@ test.describe("Workspace Manager V2 bootstrap", () => {
526530
await expect(page.locator('[data-launch-mode-nav="workspace"] button')).toHaveText(["Generate Image", "Return to Workspace"]);
527531
await expect(page.locator("#executeBtn")).toBeVisible();
528532
await expect(page.locator("#executeBtn")).toBeEnabled();
529-
await expect(page.locator("#repoSelectedValue")).toHaveText(server.repoRoot);
533+
await expect(page.locator("#repoSelectedValue")).toHaveText(manifestRepoPath(server));
530534
await expect(page.locator("#pickRepoBtn")).toBeHidden();
531535
await expect(page.locator("#workspaceContextValue")).toHaveCount(0);
532536
await expect(page.locator("#repoDestinationContent")).not.toContainText("Workspace launch");
@@ -540,11 +544,12 @@ test.describe("Workspace Manager V2 bootstrap", () => {
540544
await expect(page.locator("#lastGeneratedImagePreview")).toBeVisible();
541545
await expect(page.locator("#lastGeneratedImageMeta")).toHaveText("Preview target: games/Asteroids/assets/images/preview.png");
542546
const absoluteAsteroidsPreviewPath = path.join(server.repoRoot, "games", "Asteroids", "assets", "images", "preview.svg");
547+
const displayedAsteroidsPreviewPath = `${manifestRepoPath(server)}/games/Asteroids/assets/images/preview.svg`;
543548
await expect(page.locator("#log")).toContainText("OK Workspace launch context hydrated for Asteroids.");
544549
await expect(page.locator("#log")).toContainText("Workspace repoRoot display label available: HTML-JavaScript-Gaming.");
545-
await expect(page.locator("#log")).toContainText(`Workspace repoPath available: ${server.repoRoot}.`);
546-
await expect(page.locator("#log")).toContainText(`Resolved repoPath: ${server.repoRoot}`);
547-
await expect(page.locator("#log")).toContainText(`Resolved absolute preview output path: ${absoluteAsteroidsPreviewPath}`);
550+
await expect(page.locator("#log")).toContainText(`Workspace repoPath available: ${manifestRepoPath(server)}.`);
551+
await expect(page.locator("#log")).toContainText(`Resolved repoPath: ${manifestRepoPath(server)}`);
552+
await expect(page.locator("#log")).toContainText(`Resolved absolute preview output path: ${displayedAsteroidsPreviewPath}`);
548553
await expect(page.locator("#log")).not.toContainText("Direct preview write unavailable");
549554
await expect(page.locator("#log")).not.toContainText("Unable to resolve absolute repoRoot");
550555
await expect(page.locator("#log")).not.toContainText("/__workspace-manager-v2/repo-root");
@@ -567,10 +572,10 @@ test.describe("Workspace Manager V2 bootstrap", () => {
567572
});
568573
await page.locator("#executeBtn").click();
569574
await expect(page.locator("#log")).toContainText("Workspace launch direct preview write target: games/Asteroids/assets/images/preview.svg.", { timeout: 20000 });
570-
await expect(page.locator("#log")).toContainText(`Workspace launch absolute preview output path: ${absoluteAsteroidsPreviewPath}.`, { timeout: 20000 });
575+
await expect(page.locator("#log")).toContainText(`Workspace launch absolute preview output path: ${displayedAsteroidsPreviewPath}.`, { timeout: 20000 });
571576
await expect(page.locator("#log")).toContainText("Direct preview write target: games/Asteroids/assets/images/preview.svg", { timeout: 20000 });
572-
await expect(page.locator("#log")).toContainText(`Direct preview absolute path: ${absoluteAsteroidsPreviewPath}`, { timeout: 20000 });
573-
await expect(page.locator("#log")).toContainText(`OK Direct preview write completed: ${absoluteAsteroidsPreviewPath}`, { timeout: 20000 });
577+
await expect(page.locator("#log")).toContainText(`Direct preview absolute path: ${displayedAsteroidsPreviewPath}`, { timeout: 20000 });
578+
await expect(page.locator("#log")).toContainText(`OK Direct preview write completed: ${displayedAsteroidsPreviewPath}`, { timeout: 20000 });
574579
await expect(page.locator("#log")).toContainText("OK Asteroids", { timeout: 20000 });
575580
expect(previewDownloadOpened).toBe(false);
576581
expect(server.previewWrites.get("games/Asteroids/assets/images/preview.svg")).toContain("<svg");
@@ -687,16 +692,17 @@ test.describe("Workspace Manager V2 bootstrap", () => {
687692

688693
await page.locator("#activeGameSelect").selectOption("GravityWell");
689694
await expect(page.locator("#activeGameSummary")).toContainText("games/GravityWell/");
690-
await expect(page.locator("#activeGameSummary")).toContainText("Select Repo");
695+
await expect(page.locator("#activeGameSummary")).toContainText(`Repo path: ${manifestRepoPath(server)}.`);
691696
await expect(page.locator("#workspaceContextOutput")).toHaveValue(/"gameRoot": "games\/GravityWell\/"/);
692697
await expect(page.locator("#workspaceContextOutput")).toHaveValue(/"assetsPath": "games\/GravityWell\/assets"/);
693698
await expect(page.locator("#workspaceContextOutput")).toHaveValue(/"assets.image.preview.preview"/);
694699
await expect(page.locator("#workspaceContextOutput")).not.toHaveValue(/"assets.image.background.preview"/);
695700
await expect(page.locator("#workspaceContextOutput")).not.toHaveValue(/"asset-browser"|"palette-browser"|"vector-map-editor"/);
696701
await expect(page.locator('[data-workspace-tool-id="asset-manager-v2"]')).toContainText("1 managed assets");
697702
await expect(page.locator('[data-workspace-tool-id="palette-manager-v2"]')).toContainText("10 palette swatches");
698-
await expect(page.locator('[data-workspace-tool-id="preview-generator-v2"]')).toContainText("Select Repo");
703+
await expect(page.locator('[data-workspace-tool-id="preview-generator-v2"]')).toContainText("Schema-valid manifest");
699704
const gravityManifest = JSON.parse(await page.locator("#workspaceContextOutput").inputValue());
705+
expect(gravityManifest.repoPath).toBe(manifestRepoPath(server));
700706
expect(Object.keys(gravityManifest.tools).sort()).toEqual(["asset-manager-v2", "palette-manager-v2"]);
701707
expect(gravityManifest.tools["asset-manager-v2"].assets["assets.image.preview.preview"]).toEqual({
702708
path: "assets/images/preview.svg",
@@ -707,18 +713,31 @@ test.describe("Workspace Manager V2 bootstrap", () => {
707713
});
708714
expect(gravityManifest.tools["asset-manager-v2"].assets["assets.image.background.preview"]).toBeUndefined();
709715

716+
await page.locator('[data-workspace-tool-id="preview-generator-v2"]').click();
717+
await expect(page).toHaveURL(/preview-generator-v2\/index\.html.*launch=workspace/);
718+
await expect(page.locator("#repoSelectedValue")).toHaveText(manifestRepoPath(server));
719+
await expect(page.locator("#pickRepoBtn")).toBeHidden();
720+
await expect(page.locator("#sampleList")).toHaveValue("GravityWell");
721+
await expect(page.locator("#previewTargetValue")).toHaveText("games/GravityWell/assets/images/preview.svg");
722+
await expect(page.locator("#executeBtn")).toBeEnabled();
723+
await expect(page.locator("#log")).toContainText(`Workspace repoPath available: ${manifestRepoPath(server)}.`);
724+
await expect(page.locator("#log")).toContainText("Generated preview target: games/GravityWell/assets/images/preview.svg");
725+
await page.locator("#returnToWorkspaceButton").click();
726+
await expect(page).toHaveURL(/workspace-manager-v2\/index\.html\?hostContextId=workspace-manager-v2-/);
727+
710728
await page.locator("#activeGameSelect").selectOption("Pong");
711729
await expect(page.locator("#activeGameSummary")).toContainText("games/Pong/");
712-
await expect(page.locator("#activeGameSummary")).toContainText("Select Repo");
730+
await expect(page.locator("#activeGameSummary")).toContainText(`Repo path: ${manifestRepoPath(server)}.`);
713731
await expect(page.locator("#workspaceContextOutput")).toHaveValue(/"gameRoot": "games\/Pong\/"/);
714732
await expect(page.locator("#workspaceContextOutput")).toHaveValue(/"assetsPath": "games\/Pong\/assets"/);
715733
await expect(page.locator("#workspaceContextOutput")).toHaveValue(/"assets.image.preview.preview"/);
716734
await expect(page.locator("#workspaceContextOutput")).not.toHaveValue(/"assets.image.background.preview"/);
717735
await expect(page.locator("#workspaceContextOutput")).not.toHaveValue(/"asset-browser"|"palette-browser"|"vector-map-editor"/);
718736
await expect(page.locator('[data-workspace-tool-id="asset-manager-v2"]')).toContainText("1 managed assets");
719737
await expect(page.locator('[data-workspace-tool-id="palette-manager-v2"]')).toContainText("8 palette swatches");
720-
await expect(page.locator('[data-workspace-tool-id="preview-generator-v2"]')).toContainText("Select Repo");
738+
await expect(page.locator('[data-workspace-tool-id="preview-generator-v2"]')).toContainText("Schema-valid manifest");
721739
const pongManifest = JSON.parse(await page.locator("#workspaceContextOutput").inputValue());
740+
expect(pongManifest.repoPath).toBe(manifestRepoPath(server));
722741
expect(Object.keys(pongManifest.tools).sort()).toEqual(["asset-manager-v2", "palette-manager-v2"]);
723742
expect(pongManifest.tools["asset-manager-v2"].assets["assets.image.preview.preview"]).toEqual({
724743
path: "assets/images/preview.svg",
@@ -729,6 +748,18 @@ test.describe("Workspace Manager V2 bootstrap", () => {
729748
});
730749
expect(pongManifest.tools["asset-manager-v2"].assets["assets.image.background.preview"]).toBeUndefined();
731750

751+
await page.locator('[data-workspace-tool-id="preview-generator-v2"]').click();
752+
await expect(page).toHaveURL(/preview-generator-v2\/index\.html.*launch=workspace/);
753+
await expect(page.locator("#repoSelectedValue")).toHaveText(manifestRepoPath(server));
754+
await expect(page.locator("#pickRepoBtn")).toBeHidden();
755+
await expect(page.locator("#sampleList")).toHaveValue("Pong");
756+
await expect(page.locator("#previewTargetValue")).toHaveText("games/Pong/assets/images/preview.svg");
757+
await expect(page.locator("#executeBtn")).toBeEnabled();
758+
await expect(page.locator("#log")).toContainText(`Workspace repoPath available: ${manifestRepoPath(server)}.`);
759+
await expect(page.locator("#log")).toContainText("Generated preview target: games/Pong/assets/images/preview.svg");
760+
await page.locator("#returnToWorkspaceButton").click();
761+
await expect(page).toHaveURL(/workspace-manager-v2\/index\.html\?hostContextId=workspace-manager-v2-/);
762+
732763
expect(pageErrors).toEqual([]);
733764
} finally {
734765
await coverageReporter.stop(page);
@@ -819,10 +850,11 @@ test.describe("Workspace Manager V2 bootstrap", () => {
819850
await expect(page.locator('[data-workspace-tool-id="asset-manager-v2"]')).toContainText("0 managed assets");
820851
await expect(page.locator('[data-workspace-tool-id="workspace-manager-v2"]')).toHaveCount(0);
821852
await expect(page.locator('[data-workspace-tool-id="palette-manager-v2"]')).toContainText("3 palette swatches");
822-
await expect(page.locator('[data-workspace-tool-id="preview-generator-v2"]')).toContainText("Select Repo");
853+
await expect(page.locator('[data-workspace-tool-id="preview-generator-v2"]')).toContainText("Schema-valid manifest");
823854
await expect(page.locator("#workspaceContextOutput")).toHaveValue(/"id": "workspace-manager-v2-UAT-template"/);
824855
await expect(page.locator("#workspaceContextOutput")).toHaveValue(/"gameRoot": "games\/_template\/"/);
825856
await expect(page.locator("#workspaceContextOutput")).toHaveValue(/"assetsPath": "games\/_template\/assets"/);
857+
expect(JSON.parse(await page.locator("#workspaceContextOutput").inputValue()).repoPath).toBe(manifestRepoPath(server));
826858
await expect(page.locator("#workspaceContextOutput")).toHaveValue(/"sourceId": "games\/_template\/workspace-manager-v2-UAT.manifest.json"/);
827859
await expect(page.locator("#statusLog")).toHaveValue(/OK Loaded UAT Workspace Manager V2 manifest workspace-manager-v2-UAT-template from \/games\/_template\/workspace-manager-v2-UAT\.manifest\.json\./);
828860

tools/preview-generator-v2/PreviewGeneratorV2App.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -80,7 +80,7 @@ function isAbsoluteFilesystemPath(value) {
8080
}
8181

8282
function useWindowsPathSeparator(pathValue) {
83-
return /^[A-Za-z]:[\\/]/.test(pathValue) || String(pathValue || "").includes("\\");
83+
return String(pathValue || "").includes("\\");
8484
}
8585

8686
function trimFilesystemTrailingSeparators(pathValue) {

0 commit comments

Comments
 (0)