Skip to content

Commit 6db9cf5

Browse files
author
DavidQ
committed
Add manifest preview image selection and fix Preview Generator workspace hydration - PR_26127_006-preview-image-manifest-selection-and-launch-hydration
1 parent bbf041b commit 6db9cf5

13 files changed

Lines changed: 183 additions & 44 deletions
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
# PR_26127_006-preview-image-manifest-selection-and-launch-hydration
2+
3+
## Scope
4+
- Added a schema-valid manifest repo root context through `repoRoot`.
5+
- Added `tools.asset-manager-v2.previewImagePath` as the explicit manifest preview image source of truth.
6+
- Added `preview-image` as an Asset Manager V2 image role.
7+
- Moved Preview Generator V2 to the Workspace Manager V2 Utilities grouping.
8+
- Kept deprecated `tools/workspace-v2` and sample JSON unchanged.
9+
10+
## Asset Manager V2 Notes
11+
- Image role options now include `preview-image`.
12+
- Adding or updating an image asset with role `preview-image` writes that asset path into `tools.asset-manager-v2.previewImagePath`.
13+
- If multiple preview-image assets exist, the later sorted asset ID is used as the current preview image override.
14+
- `previewImagePath` must match an image asset with role `preview-image` when present.
15+
16+
## Workspace Manifest Notes
17+
- `games/Asteroids/game.manifest.json` now declares `repoRoot: HTML-JavaScript-Gaming`.
18+
- The Asteroids manifest now includes `tools.asset-manager-v2.previewImagePath: assets/images/bezel.png`.
19+
- The Asteroids manifest includes `assets.image.preview-image.bezel` so the preview image path is schema-backed by an Asset Manager V2 asset record.
20+
- Temporary UAT manifest now includes the same repo root context.
21+
22+
## Preview Generator V2 Hydration Notes
23+
- Workspace Manager launch reads repo display from `manifest.repoRoot`; it no longer shows the game label or asset folder as the repo root.
24+
- Preview image path reads from `tools.asset-manager-v2.previewImagePath`; there is no bezel-derived hidden default.
25+
- Generate Image stays disabled until the manifest preview image validates and the picked repo root matches the manifest repo root.
26+
- Workspace launch displays hydrated context text and logs the manifest preview path.
27+
28+
## Validation
29+
- `npm run test:workspace-v2` passed: 24/24.
30+
- Changed runtime JavaScript passed `node --check`.
31+
- Playwright V8 coverage report was regenerated at `docs/dev/reports/playwright_v8_coverage_report.txt`.
32+
33+
## Manual Validation
34+
- Open Workspace Manager V2, load Asteroids, confirm Preview Generator V2 appears under Utilities.
35+
- Launch Asset Manager V2 from Workspace Manager V2, choose Image, pick an image, select role `preview-image`, add the asset, return to Workspace Manager V2, and export the manifest.
36+
- Confirm the exported manifest includes `tools.asset-manager-v2.previewImagePath` matching the selected preview-image asset path.
37+
- Launch Preview Generator V2 from Workspace Manager V2 and confirm Repo selected shows `HTML-JavaScript-Gaming`, workspace context shows hydrated, preview target uses the manifest preview image path, and Generate Image enables only after picking the matching repo root.
38+
39+
## Out Of Scope
40+
- Full samples smoke test skipped; this PR is Workspace/Asset/Preview V2 scoped.
41+
- No deprecated `tools/workspace-v2` changes.
42+
- No sample JSON changes.

games/Asteroids/game.manifest.json

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
"gameId": "Asteroids",
99
"gameRoot": "games/Asteroids/",
1010
"assetsPath": "games/Asteroids/assets",
11+
"repoRoot": "HTML-JavaScript-Gaming",
1112
"tools": {
1213
"palette-manager-v2": {
1314
"$schema": "tools/schemas/tools/palette-manager-v2.schema.json",
@@ -79,6 +80,7 @@
7980
"version": 1,
8081
"name": "Asteroids Asset Manager V2 Registry",
8182
"source": "manifest",
83+
"previewImagePath": "assets/images/bezel.png",
8284
"assets": {
8385
"assets.audio.music.beat-1": {
8486
"path": "assets/audio/beat1.wav",
@@ -173,6 +175,13 @@
173175
"stretchOverride": {
174176
"uniformEdgeStretchPx": 10
175177
}
178+
},
179+
"assets.image.preview-image.bezel": {
180+
"path": "assets/images/bezel.png",
181+
"type": "image",
182+
"kind": "png",
183+
"role": "preview-image",
184+
"source": "manifest"
176185
}
177186
}
178187
},

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
"gameId": "Asteroids",
99
"gameRoot": "games/Asteroids/",
1010
"assetsPath": "games/Asteroids/assets",
11+
"repoRoot": "HTML-JavaScript-Gaming",
1112
"tools": {
1213
"palette-manager-v2": {
1314
"$schema": "tools/schemas/tools/palette-manager-v2.schema.json",

tests/playwright/tools/AssetManagerV2.spec.mjs

Lines changed: 19 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -422,6 +422,8 @@ test.describe("Asset Manager V2", () => {
422422
await expect(page.locator("#assetRoleSelect")).toHaveValue("music");
423423
await page.locator("#assetKindImage").check();
424424
await expect(page.locator("#assetRoleSelect")).toHaveValue("sprite");
425+
await expect(page.locator("#assetRoleSelect option")).toHaveText(["sprite", "background", "bezel", "preview-image", "ui"]);
426+
await expect(page.locator("#assetRoleSelect")).toHaveAttribute("title", "Allowed roles for image: sprite, background, bezel, preview-image, ui");
425427
await page.locator("#pickAssetFileButton").click();
426428
const pickerOptions = await page.evaluate(() => window.__assetManagerV2PickerOptions.at(-1));
427429
expect(pickerOptions.types[0].description).toBe("Image assets");
@@ -542,7 +544,8 @@ test.describe("Asset Manager V2", () => {
542544
});
543545
await page.locator("#pickAssetFileButton").click();
544546
await expect(page.locator("#assetRoleSelect")).toHaveValue("sprite");
545-
await expect(page.locator("#assetIdInput")).toHaveValue("assets.image.sprite.preview");
547+
await page.locator("#assetRoleSelect").selectOption("preview-image");
548+
await expect(page.locator("#assetIdInput")).toHaveValue("assets.image.preview-image.preview");
546549
await page.locator("#addAssetButton").click();
547550

548551
await queueAssetFile(page, {
@@ -693,8 +696,8 @@ test.describe("Asset Manager V2", () => {
693696
},
694697
{
695698
deleteTopRight: true,
696-
typeRole: "image:sprite",
697-
id: "assets.image.sprite.preview",
699+
typeRole: "image:preview-image",
700+
id: "assets.image.preview-image.preview",
698701
textLeftAligned: true,
699702
hasSeparateDeleteButton: false,
700703
hasInlineDelete: true,
@@ -709,8 +712,8 @@ test.describe("Asset Manager V2", () => {
709712
idFontWeight: 500,
710713
typeRoleFontWeight: 800,
711714
rowGap: 2,
712-
text: "X\nimage:sprite\nassets.image.sprite.preview",
713-
tooltip: "id: assets.image.sprite.preview\ntype: image\nkind: png\nrole: sprite\npath: assets/images/preview.png"
715+
text: "X\nimage:preview-image\nassets.image.preview-image.preview",
716+
tooltip: "id: assets.image.preview-image.preview\ntype: image\nkind: png\nrole: preview-image\npath: assets/images/preview.png"
714717
}
715718
]);
716719
const tileLayout = await page.locator("#assetList").evaluate((list) => {
@@ -1267,14 +1270,14 @@ test.describe("Asset Manager V2", () => {
12671270
await expect(page.locator("#returnToWorkspaceButton")).toBeEnabled();
12681271
await expect(page.locator("#workspaceInsertAssetsButton")).toHaveCount(0);
12691272
await expect(page.locator("#workspaceCopyManifestButton")).toHaveCount(0);
1270-
await expect(page.locator("#statusLog")).toHaveValue(/Workspace Manager V2 loaded 13 validated assets from tools\.asset-manager-v2\.assets/);
1273+
await expect(page.locator("#statusLog")).toHaveValue(/Workspace Manager V2 loaded 14 validated assets from tools\.asset-manager-v2\.assets/);
12711274
await expect(page.locator("#statusLog")).toHaveValue(/Workspace Manager V2 loaded \d+ palette colors from active palette context/);
12721275
const hostContextId = await page.evaluate(() => new URL(window.location.href).searchParams.get("hostContextId"));
12731276
const initialAssetCount = await page.evaluate((id) => {
12741277
const context = JSON.parse(sessionStorage.getItem(id));
12751278
return Object.keys(context.tools["asset-manager-v2"].assets).length;
12761279
}, hostContextId);
1277-
expect(initialAssetCount).toBe(13);
1280+
expect(initialAssetCount).toBe(14);
12781281
const workspacePreviewContext = await page.evaluate(async () => {
12791282
const { WorkspaceBridge } = await import("/tools/asset-manager-v2/js/services/WorkspaceBridge.js");
12801283
return new WorkspaceBridge({ windowRef: window }).readWorkspacePreviewContext();
@@ -1313,6 +1316,8 @@ test.describe("Asset Manager V2", () => {
13131316
await page.locator("#pickAssetFileButton").click();
13141317
await expect(page.locator("#assetIdInput")).toHaveValue("assets.image.sprite.preview");
13151318
await expect(page.locator("#assetPathInput")).toHaveValue("assets/images/preview.png");
1319+
await page.locator("#assetRoleSelect").selectOption("preview-image");
1320+
await expect(page.locator("#assetIdInput")).toHaveValue("assets.image.preview-image.preview");
13161321
await page.locator("#addAssetButton").click();
13171322
await expect(page.locator('#assetPreview [data-preview-type="image"][data-preview-kind="png"] img')).toHaveAttribute("src", "/games/Asteroids/assets/images/preview.png");
13181323

@@ -1373,7 +1378,7 @@ test.describe("Asset Manager V2", () => {
13731378
await expect(page.locator("#inspectorOutput")).toContainText("\"type\": \"color\"");
13741379
await expect(page.locator("#inspectorOutput")).toContainText("\"kind\": \"hex\"");
13751380
await expect(page.locator("#inspectorOutput")).toContainText("\"name\": \"HUD Blue\"");
1376-
await expect(page.locator("#statusLog")).toHaveValue(/OK Workspace Manager V2 session manifest now has 17 validated assets\./);
1381+
await expect(page.locator("#statusLog")).toHaveValue(/OK Workspace Manager V2 session manifest now has 18 validated assets\./);
13771382

13781383
const storedContext = await page.evaluate((id) => JSON.parse(sessionStorage.getItem(id)), hostContextId);
13791384
expect(storedContext.documentKind).toBe("workspace-manifest");
@@ -1382,7 +1387,8 @@ test.describe("Asset Manager V2", () => {
13821387
expect(storedContext.workspaceManifest).toBeUndefined();
13831388
expect(storedContext.tools["asset-browser"]).toBeUndefined();
13841389
expect(storedContext.tools["palette-browser"]).toBeUndefined();
1385-
expect(Object.keys(storedContext.tools["asset-manager-v2"].assets)).toHaveLength(17);
1390+
expect(Object.keys(storedContext.tools["asset-manager-v2"].assets)).toHaveLength(18);
1391+
expect(storedContext.tools["asset-manager-v2"].previewImagePath).toBe("assets/images/preview.png");
13861392
expect(storedContext.tools["asset-manager-v2"].assets["assets.audio.sound.fire"]).toEqual({
13871393
path: "assets/audio/fire.wav",
13881394
type: "audio",
@@ -1404,11 +1410,11 @@ test.describe("Asset Manager V2", () => {
14041410
role: "ui",
14051411
source: "asset-manager-v2"
14061412
});
1407-
expect(storedContext.tools["asset-manager-v2"].assets["assets.image.sprite.preview"]).toEqual({
1413+
expect(storedContext.tools["asset-manager-v2"].assets["assets.image.preview-image.preview"]).toEqual({
14081414
path: "assets/images/preview.png",
14091415
type: "image",
14101416
kind: "png",
1411-
role: "sprite",
1417+
role: "preview-image",
14121418
source: "asset-manager-v2"
14131419
});
14141420
expect(storedContext.tools["asset-manager-v2"].assets["assets.color.hud.primary-hud.hud-blue"]).toEqual({
@@ -1439,7 +1445,8 @@ test.describe("Asset Manager V2", () => {
14391445
const download = await downloadPromise;
14401446
expect(download.suggestedFilename()).toBe("workspace-manager-v2-Asteroids.workspace.manifest.json");
14411447
const savedManifest = JSON.parse(await readFile(await download.path(), "utf8"));
1442-
expect(Object.keys(savedManifest.tools["asset-manager-v2"].assets)).toHaveLength(17);
1448+
expect(Object.keys(savedManifest.tools["asset-manager-v2"].assets)).toHaveLength(18);
1449+
expect(savedManifest.tools["asset-manager-v2"].previewImagePath).toBe("assets/images/preview.png");
14431450
expect(savedManifest.tools["asset-manager-v2"].assets["assets.audio.sound.laser"]).toEqual(storedContext.tools["asset-manager-v2"].assets["assets.audio.sound.laser"]);
14441451
expect(savedManifest.tools["asset-manager-v2"].assets["assets.color.hud.primary-hud.hud-blue"]).toEqual(storedContext.tools["asset-manager-v2"].assets["assets.color.hud.primary-hud.hud-blue"]);
14451452
expect(savedManifest.tools["vector-map-editor"].vectorMapDocument.vectors.map((vector) => vector.id)).toContain("vector.asteroids.ship");

0 commit comments

Comments
 (0)