Skip to content

Commit 64b879b

Browse files
author
DavidQ
committed
Integrate Workspace Manager V2 session launch with Asset Manager V2 - PR_26126_113-workspace-manager-v2-session-launch-integration
1 parent b36241f commit 64b879b

11 files changed

Lines changed: 335 additions & 121 deletions
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
# PR_26126_113 Asset Manager Integration Notes
2+
3+
## Workspace Bridge
4+
- `WorkspaceBridge` now accepts production session context only from Workspace Manager V2.
5+
- Legacy Workspace V2-style context is rejected before Asset Manager V2 enters workspace mode.
6+
- Palette swatches are read from Workspace Manager V2 `activePalette`, not from fallback query parameters.
7+
- Preview context now carries `workspaceAssetsPath`, `workspaceGameId`, and `workspaceGameRoot`.
8+
9+
## Preview Path Integration
10+
- Asset Manager V2 preview helpers resolve asset-backed preview URLs through the Workspace Manager-owned `assetsPath`.
11+
- Workspace preview paths resolve under `/games/<game>/assets/...` when a valid session context is active.
12+
- Missing or invalid Workspace Manager V2 preview context logs a visible Status failure.
13+
14+
## Asset Insert Integration
15+
- Workspace insert continues to target the Workspace V2 asset schema location inside the active manifest payload.
16+
- Insert success/failure messages are routed through Status and now identify the Workspace Manager V2 session path.
17+
- The temporary `?workspace=UAT` path is unchanged and remains isolated for UAT-only testing.
18+
19+
## Scope
20+
- Deprecated `tools/workspace-v2/` was not modified.
21+
- Sample JSON was not modified.
22+
- No samples/tools workspace roots were added.
23+
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
# PR_26126_113 Manual Validation Notes
2+
3+
## Automated Validation
4+
- `npm run test:asset-manager-v2` passed.
5+
- Result: 8 Playwright tests passed.
6+
- `npm run test:workspace-v2` passed.
7+
- Result: 19 Playwright tests passed.
8+
9+
## Manual Checks
10+
1. Open `tools/workspace-manager-v2/index.html`.
11+
- Expected: Workspace Manager V2 can select the active Asteroids game context.
12+
- Expected: Workspace Manager V2 session output includes `gameRoot`, `assetsPath`, and top-level `activePalette`.
13+
2. Launch Asset Manager V2 from Workspace Manager V2.
14+
- Expected: URL includes `launch=workspace` and `fromTool=workspace-manager-v2`.
15+
- Expected: URL does not use `?workspace=prod`.
16+
- Expected: Asset Manager V2 loads active game, palette, and assets path context from session state.
17+
3. Open `tools/asset-manager-v2/index.html`.
18+
- Expected: direct launch hard-fails to the launch guard overlay.
19+
4. Open `tools/asset-manager-v2/index.html?workspace=prod`.
20+
- Expected: direct production launch hard-fails to the launch guard overlay.
21+
5. Open `tools/asset-manager-v2/index.html?workspace=UAT`.
22+
- Expected: temporary UAT launch continues to seed the isolated Asteroids game root, assets path, and sample palette.
23+
24+
## Scope Checks
25+
- No changed files under `tools/workspace-v2/`.
26+
- No sample JSON changes.
27+
- No samples/tools workspace roots were added.
28+
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
# PR_26126_113 Workspace Session Launch Notes
2+
3+
## Session Ownership
4+
- Workspace Manager V2 now writes the production Asset Manager V2 launch context as a Workspace Manager-owned session payload.
5+
- The session context owns:
6+
- `gameId`
7+
- `gameRoot`
8+
- `assetsPath`
9+
- `activePalette`
10+
- `workspaceManifest`
11+
- `activePalette` is persisted as a top-level context value with `source: "workspace-manager-v2"` and the active palette swatches.
12+
- `assetsPath` is derived from the active game root as `games/<game>/assets`.
13+
14+
## Production Launch Contract
15+
- Asset Manager V2 production launch requires:
16+
- `launch=workspace`
17+
- `fromTool=workspace-manager-v2`
18+
- a valid `hostContextId`
19+
- a session payload with `version: "workspace-manager-v2"`
20+
- `toolId: "asset-manager-v2"`
21+
- games-only `gameRoot` and `assetsPath`
22+
- non-empty active palette swatches
23+
- Direct launch without valid Workspace Manager V2 session/context continues to show the launch guard overlay.
24+
- `?workspace=prod` remains unsupported and is treated as an invalid direct-launch state.
25+
- `?workspace=UAT` remains the only temporary URL-based UAT path.
26+
27+
## Games-Only Guard
28+
- Context validation rejects workspace roots outside `games/`.
29+
- Context validation rejects paths containing `samples/` or `tools/`.
30+
- `assetsPath` must match the active game root plus `/assets`.
31+

tests/playwright/tools/AssetManagerV2.spec.mjs

Lines changed: 141 additions & 81 deletions
Large diffs are not rendered by default.

tests/playwright/tools/WorkspaceManagerV2.spec.mjs

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -150,6 +150,8 @@ test.describe("Workspace Manager V2 bootstrap", () => {
150150
await expect(page.locator("#launchContextSummary")).toHaveText("Session launch context is ready for Asteroids.");
151151
await expect(page.locator("#workspaceContextOutput")).toContainText('"gameRoot": "games/Asteroids/"');
152152
await expect(page.locator("#workspaceContextOutput")).toContainText('"assetsPath": "games/Asteroids/assets"');
153+
await expect(page.locator("#workspaceContextOutput")).toContainText('"activePalette"');
154+
await expect(page.locator("#workspaceContextOutput")).toContainText('"source": "workspace-manager-v2"');
153155
await expect(page.locator("#workspaceContextOutput")).toContainText('"owner": "workspace-manager-v2"');
154156
await expect(page.locator("#workspaceContextOutput")).not.toContainText("samples/");
155157
await expect(page.locator("#workspaceContextOutput")).not.toContainText("tools/");
@@ -165,15 +167,16 @@ test.describe("Workspace Manager V2 bootstrap", () => {
165167
await expect(page.locator("#assetLaunchGuard")).toBeHidden();
166168
await expect(page.locator(".asset-manager-v2__tool__menu")).toBeHidden();
167169
await expect(page.locator(".asset-manager-v2__workspace__menu")).toBeVisible();
168-
await expect(page.locator("#statusLog")).toHaveValue(/Workspace mode loaded 0 validated assets from tools\.asset-browser\.assets/);
169-
await expect(page.locator("#statusLog")).toHaveValue(/Workspace mode loaded \d+ palette colors from tools\.palette-browser\.swatches/);
170+
await expect(page.locator("#statusLog")).toHaveValue(/Workspace Manager V2 loaded 0 validated assets from tools\.asset-browser\.assets/);
171+
await expect(page.locator("#statusLog")).toHaveValue(/Workspace Manager V2 loaded \d+ palette colors from active palette context/);
170172

171173
const workspacePreviewContext = await page.evaluate(async () => {
172174
const { WorkspaceBridge } = await import("/tools/asset-manager-v2/js/services/WorkspaceBridge.js");
173175
return new WorkspaceBridge({ windowRef: window }).readWorkspacePreviewContext();
174176
});
175177
expect(workspacePreviewContext).toEqual({
176178
workspaceMode: true,
179+
workspaceAssetsPath: "games/Asteroids/assets",
177180
workspaceGameId: "Asteroids",
178181
workspaceGameRoot: "games/Asteroids/"
179182
});
@@ -187,6 +190,8 @@ test.describe("Workspace Manager V2 bootstrap", () => {
187190
expect(storedContext.version).toBe("workspace-manager-v2");
188191
expect(storedContext.gameRoot).toBe("games/Asteroids/");
189192
expect(storedContext.assetsPath).toBe("games/Asteroids/assets");
193+
expect(storedContext.activePalette.source).toBe("workspace-manager-v2");
194+
expect(storedContext.activePalette.swatches.length).toBeGreaterThan(0);
190195
expect(storedContext.workspaceManifest.tools["palette-browser"].swatches.length).toBeGreaterThan(0);
191196
expect(storedContext.workspaceManifest.tools["asset-browser"].assets).toEqual({});
192197
expect(JSON.stringify(storedContext)).not.toMatch(/samples\//i);

tools/asset-manager-v2/js/AssetManagerV2App.js

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -125,8 +125,8 @@ export class AssetManagerV2App {
125125
}
126126

127127
const previewContext = this.workspaceBridge.readWorkspacePreviewContext();
128-
if (!previewContext.workspaceGameId || !previewContext.workspaceGameRoot) {
129-
return { ok: false, reason: "Workspace game context is missing." };
128+
if (!previewContext.workspaceGameId || !previewContext.workspaceGameRoot || !previewContext.workspaceAssetsPath) {
129+
return { ok: false, reason: "Workspace Manager V2 gameRoot or assetsPath context is missing." };
130130
}
131131

132132
const paletteResult = this.workspaceBridge.readWorkspacePaletteSwatches();
@@ -193,7 +193,7 @@ export class AssetManagerV2App {
193193
this.selectedAssetId = Object.keys(this.assets)[0] || "";
194194
this.undoStack = [];
195195
this.redoStack = [];
196-
this.statusLog.ok(`Workspace mode loaded ${Object.keys(this.assets).length} validated assets from tools.asset-browser.assets.`);
196+
this.statusLog.ok(`Workspace Manager V2 loaded ${Object.keys(this.assets).length} validated assets from tools.asset-browser.assets.`);
197197
this.missingFileAssetIds = await this.logMissingReferencedFiles(this.assets);
198198
}
199199

@@ -220,7 +220,7 @@ export class AssetManagerV2App {
220220
return;
221221
}
222222
this.assetForm.setPaletteSwatches(result.swatches);
223-
this.statusLog.ok(`Workspace mode loaded ${result.swatches.length} palette colors from tools.palette-browser.swatches.`);
223+
this.statusLog.ok(`Workspace Manager V2 loaded ${result.swatches.length} palette colors from active palette context.`);
224224
}
225225

226226
previewOptions() {
@@ -555,10 +555,10 @@ export class AssetManagerV2App {
555555

556556
async copyWorkspaceManifest() {
557557
if (!this.lastWorkspaceManifest) {
558-
this.statusLog.fail("No Workspace V2 manifest has been inserted in this session.");
558+
this.statusLog.fail("No Workspace Manager V2 manifest has been inserted in this session.");
559559
return;
560560
}
561-
await this.copyText(JSON.stringify(this.lastWorkspaceManifest, null, 2), "Workspace V2 manifest JSON copied.");
561+
await this.copyText(JSON.stringify(this.lastWorkspaceManifest, null, 2), "Workspace Manager V2 manifest JSON copied.");
562562
}
563563

564564
async copyText(value, successMessage) {
@@ -588,7 +588,7 @@ export class AssetManagerV2App {
588588
}
589589
this.lastWorkspaceManifest = result.workspaceManifest;
590590
this.inspector.showObject(result.workspaceManifest);
591-
this.statusLog.ok(`Inserted ${Object.keys(validation.payload.assets).length} validated assets into Workspace V2 tools.asset-browser.assets.`);
591+
this.statusLog.ok(`Inserted ${Object.keys(validation.payload.assets).length} validated assets into Workspace Manager V2 tools.asset-browser.assets.`);
592592
this.refreshActions();
593593
}
594594

tools/asset-manager-v2/js/assetPreviewHelpers.js

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,16 +22,25 @@ function workspaceGameRoot(options = {}) {
2222
return gameId ? `games/${gameId}/` : "";
2323
}
2424

25+
function workspaceAssetsPath(options = {}) {
26+
const explicitAssetsPath = sanitizeText(options.workspaceAssetsPath || options.assetsPath).replace(/\\/g, "/").replace(/^\/+|\/+$/g, "");
27+
return /^games\/[^/]+\/assets$/i.test(explicitAssetsPath) ? explicitAssetsPath : "";
28+
}
29+
2530
function workspaceGameAssetPath(path, options = {}) {
2631
const normalizedPath = sanitizeText(path).replace(/\\/g, "/").replace(/^\/+/, "");
2732
if (!options.workspaceMode || hasUrlProtocol(normalizedPath) || /^games\//i.test(normalizedPath) || !/^assets\//i.test(normalizedPath)) {
2833
return { path, error: "" };
2934
}
35+
const assetsPath = workspaceAssetsPath(options);
36+
if (assetsPath) {
37+
return { path: `${assetsPath}/${normalizedPath.replace(/^assets\//i, "")}`, error: "" };
38+
}
3039
const gameRoot = workspaceGameRoot(options);
3140
if (!gameRoot) {
3241
return {
3342
path: "",
34-
error: `Preview path ${normalizedPath} cannot be resolved because Workspace V2 game context is missing.`
43+
error: `Preview path ${normalizedPath} cannot be resolved because Workspace Manager V2 game context is missing.`
3544
};
3645
}
3746
return { path: `${gameRoot}${normalizedPath}`, error: "" };

tools/asset-manager-v2/js/controls/ActionNavControl.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ export class ActionNavControl {
3939

4040
applyLaunchMode() {
4141
const params = new URLSearchParams(this.location.search);
42-
const mode = params.get("launch") === "workspace" || params.get("fromTool") === "workspace-v2"
42+
const mode = params.get("launch") === "workspace" && params.get("fromTool") === "workspace-manager-v2"
4343
? "workspace"
4444
: "tool";
4545
this.toolNav.hidden = mode !== "tool";

tools/asset-manager-v2/js/services/TemporaryUatWorkspace.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
// Temporary UAT-only workspace session loader. Keep this isolated so
2-
// ?workspace=UAT can be removed without touching normal Workspace V2 loading.
2+
// ?workspace=UAT can be removed without touching normal Workspace Manager V2 loading.
33
const TEMPORARY_UAT_GAME_ROOT = "games/Asteroids/";
44
const TEMPORARY_UAT_ASSETS_PATH = "games/Asteroids/assets";
55

0 commit comments

Comments
 (0)