Skip to content

Commit a3cc6d2

Browse files
author
DavidQ
committed
Remove deprecated tool registrations and align workspace tile actions - PR_26130_030-remove-deprecated-tools-and-align-tile-actions
1 parent bba939a commit a3cc6d2

35 files changed

Lines changed: 136 additions & 3113 deletions
Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
# PR_26130_030-remove-deprecated-tools-and-align-tile-actions
2+
3+
## Summary
4+
- Removed Asset Browser / Import Hub and Tile Model Converter from active tool registration, Tools Index rendering, workspace/tool shared navigation, project adapter/toolState hooks, schema metadata, starter template state, and deprecated targeted tests.
5+
- Deleted the deprecated tool implementation folders and their tool payload schemas.
6+
- Updated Workspace Manager V2 tool tiles so the action row has a fixed height and is anchored to the bottom of each tile across varied count/description text.
7+
- Added/updated Workspace Manager V2 Playwright coverage for removed registry/index/workspace launch paths and fixed tile action layout metrics.
8+
9+
## Scope Notes
10+
- No `start_of_day` files changed.
11+
- No full sample JSON alignment was attempted.
12+
- Historical docs/reports and legacy runtime compatibility references were not rewritten unless they were active current-tool availability references.
13+
- Asset Manager V2's explicit guard rejecting old `tools.asset-browser` workspace payloads remains intentionally in place as a negative validation path.
14+
15+
## Playwright Impacted
16+
Yes.
17+
18+
Validated behavior:
19+
- Asset Browser / Import Hub is absent from the Tools Index and tool registry.
20+
- Tile Model Converter is absent from the Tools Index and tool registry.
21+
- Removed tools have no active sample launch definitions and their old direct tool folders return 404.
22+
- Removed tools do not render as Workspace Manager V2 tool tiles.
23+
- Workspace Manager V2 tool tile action rows have fixed height, fixed chip height, and consistent bottom alignment.
24+
25+
Expected pass behavior:
26+
- `npm run test:workspace-v2` passes all Workspace Manager V2 tests.
27+
- Removed tool IDs are unavailable from registry/launch lookup and do not render in Workspace Manager V2.
28+
- Workspace tool action chips stay aligned at the bottom of fixed-height tiles.
29+
30+
Expected fail behavior:
31+
- Any reintroduced `asset-browser` or `tile-model-converter` registry, index, launch, or workspace tile path fails the updated Playwright assertions.
32+
- Any tile action row height or bottom-baseline drift fails the layout metric assertions.
33+
34+
## Validation
35+
- PASS: `npm run test:workspace-v2` -> 36 passed.
36+
- PASS: `node --test tests/tools/ToolSchemaStrictModeValidation.test.mjs`.
37+
- PASS: `node --check` on changed runtime/test JavaScript files spot-checked during implementation.
38+
- PASS: JSON parse check for changed JSON files.
39+
- PASS: `git diff --check`.
40+
- PASS: Playwright V8 coverage report generated at `docs/dev/reports/playwright_v8_coverage_report.txt`.
41+
42+
Coverage highlights for changed runtime JS:
43+
- `(100%) tools/renderToolsIndex.js - changed JS file with browser V8 coverage`
44+
- `(93%) tools/workspace-manager-v2/js/controls/ToolTilesControl.js - changed JS file with browser V8 coverage`
45+
- `(91%) tools/toolRegistry.js - changed JS file with browser V8 coverage`
46+
- `(32%) tools/shared/platformShell.js - changed JS file with browser V8 coverage`
47+
- `(9%) tools/shared/projectSystemAdapters.js - changed JS file with browser V8 coverage`
48+
- `(6%) tools/shared/projectToolIntegration.js - changed JS file with browser V8 coverage`
49+
50+
## Full Samples Smoke Test
51+
Skipped. This PR removes deprecated active tool availability and adjusts Workspace Manager V2 tile styling; targeted Workspace V2 Playwright coverage is the required validation gate. Full sample smoke remains out of scope and intentionally was not run.
52+
53+
## Manual Validation
54+
1. Open `tools/index.html` and confirm Asset Browser / Import Hub and Tile Model Converter are not listed.
55+
2. Open Workspace Manager V2, pick the repo, select Asteroids, and confirm the six remaining workspace tiles render without the removed tools.
56+
3. Confirm each workspace tile keeps How To Use and Read Me action chips pinned to the bottom of the tile.
57+
4. Try the old direct paths `/tools/Asset%20Browser/index.html` and `/tools/Tile%20Model%20Converter/index.html`; both should be unavailable.
58+
59+
## Review Artifacts
60+
- `docs/dev/reports/codex_review.diff`
61+
- `docs/dev/reports/codex_changed_files.txt`
62+
- `docs/dev/reports/playwright_v8_coverage_report.txt`
63+
- `tmp/PR_26130_030-remove-deprecated-tools-and-align-tile-actions_delta.zip`

tests/playwright/tools/WorkspaceManagerV2.spec.mjs

Lines changed: 43 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -977,7 +977,9 @@ test.describe("Workspace Manager V2 bootstrap", () => {
977977
await expect(textToSpeechToolCard).toBeVisible();
978978
await expect(textToSpeechToolCard.locator("a", { hasText: "Text to Speech V2" })).toHaveAttribute("href", "/tools/text2speech-V2/index.html");
979979
await expect(textToSpeechToolCard).toContainText("First-Class Tool V2 for browser speech synthesis");
980-
const toolsIndexState = await page.evaluate(() => {
980+
const toolsIndexState = await page.evaluate(async () => {
981+
const registryModule = await import("/tools/toolRegistry.js");
982+
const launchModule = await import("/tools/shared/toolLaunchSSoTData.js");
981983
const firstClassToolsSection = Array.from(document.querySelectorAll("section"))
982984
.find((section) => section.querySelector(":scope > h2")?.textContent?.trim() === "First-Class Tools");
983985
const workflowGrid = firstClassToolsSection?.querySelector("[data-active-tools-workflow-grid]");
@@ -997,9 +999,23 @@ test.describe("Workspace Manager V2 bootstrap", () => {
997999
allCards: cards.map((toolCard) => toolCard.querySelector("h3")?.textContent?.trim() || ""),
9981000
headings: Array.from(firstClassToolsSection?.querySelectorAll(":scope > h3") || [])
9991001
.map((heading) => heading.textContent.trim()),
1002+
launchIds: launchModule.listToolLaunchIds(),
10001003
paletteManagerActionClasses: actionClassesForCard("Palette Manager V2"),
10011004
plannedCards: Array.from(plannedToolsGrid?.querySelectorAll(".card h3") || [])
10021005
.map((heading) => heading.textContent.trim()),
1006+
registryIds: registryModule.getToolRegistry().map((tool) => tool.id),
1007+
removedLaunchDefinitions: {
1008+
assetBrowser: launchModule.getSampleToolLaunchDefinition("asset-browser"),
1009+
tileModelConverter: launchModule.getSampleToolLaunchDefinition("tile-model-converter")
1010+
},
1011+
removedToolLookup: {
1012+
assetBrowser: registryModule.getToolById("asset-browser"),
1013+
tileModelConverter: registryModule.getToolById("tile-model-converter")
1014+
},
1015+
removedToolPathStatuses: await Promise.all([
1016+
fetch("/tools/Asset%20Browser/index.html", { cache: "no-store" }).then((response) => response.status),
1017+
fetch("/tools/Tile%20Model%20Converter/index.html", { cache: "no-store" }).then((response) => response.status)
1018+
]),
10031019
sampleLabels: Array.from(firstClassToolsSection?.querySelectorAll(".tools-platform-card__action") || [])
10041020
.map((action) => action.textContent.trim())
10051021
.filter((label) => label.startsWith("Samples")),
@@ -1020,6 +1036,17 @@ test.describe("Workspace Manager V2 bootstrap", () => {
10201036
expect(toolsIndexState.utilitiesCards).toContain("Text to Speech V2");
10211037
expect(toolsIndexState.allCards).not.toContain("Asset Browser / Import Hub");
10221038
expect(toolsIndexState.allCards).not.toContain("Tile Model Converter");
1039+
expect(toolsIndexState.registryIds).not.toContain("asset-browser");
1040+
expect(toolsIndexState.registryIds).not.toContain("tile-model-converter");
1041+
expect(toolsIndexState.removedToolLookup).toEqual({
1042+
assetBrowser: null,
1043+
tileModelConverter: null
1044+
});
1045+
expect(toolsIndexState.launchIds).not.toContain("tool.asset-browser");
1046+
expect(toolsIndexState.launchIds).not.toContain("tool.tile-model-converter");
1047+
expect(toolsIndexState.removedLaunchDefinitions.assetBrowser.launchDefinition).toBeNull();
1048+
expect(toolsIndexState.removedLaunchDefinitions.tileModelConverter.launchDefinition).toBeNull();
1049+
expect(toolsIndexState.removedToolPathStatuses).toEqual([404, 404]);
10231050
expect(toolsIndexState.plannedCards).toContain("Piper WASM Backend");
10241051
expect(toolsIndexState.plannedCards).toContain("Optional SSML Processing Layer");
10251052
expect(toolsIndexState.plannedCards).not.toContain("Character Voice Presets");
@@ -3006,6 +3033,8 @@ test.describe("Workspace Manager V2 bootstrap", () => {
30063033
await expect(page.locator("#workspaceToolTiles [data-workspace-tool-id]")).toHaveCount(6);
30073034
await expect(page.locator('[data-workspace-tool-id="workspace-manager-v2"]')).toHaveCount(0);
30083035
await expect(page.locator('[data-workspace-tool-id="session-inspector"]')).toHaveCount(0);
3036+
await expect(page.locator('[data-workspace-tool-id="asset-browser"]')).toHaveCount(0);
3037+
await expect(page.locator('[data-workspace-tool-id="tile-model-converter"]')).toHaveCount(0);
30093038
const toolGroupMembership = await page.locator(".workspace-manager-v2__tool-group").evaluateAll((groups) => Object.fromEntries(groups.map((group) => [
30103039
group.querySelector(".workspace-manager-v2__tool-group-title")?.textContent?.trim(),
30113040
Array.from(group.querySelectorAll(".workspace-manager-v2__tool-tile-name"), (name) => name.textContent.trim())
@@ -3221,6 +3250,16 @@ test.describe("Workspace Manager V2 bootstrap", () => {
32213250
height: Math.round(tile.getBoundingClientRect().height),
32223251
width: Math.round(tile.getBoundingClientRect().width)
32233252
})));
3253+
const tileActionLayout = await page.locator("#workspaceToolTiles [data-workspace-tool-id]").evaluateAll((tiles) => tiles.map((tile) => {
3254+
const tileRect = tile.getBoundingClientRect();
3255+
const actions = tile.querySelector(".workspace-manager-v2__tool-tile-actions");
3256+
const actionRect = actions.getBoundingClientRect();
3257+
return {
3258+
actionBottomGap: Math.round(tileRect.bottom - actionRect.bottom),
3259+
actionHeight: Math.round(actionRect.height),
3260+
chipHeights: Array.from(actions.querySelectorAll(".workspace-manager-v2__tool-tile-action"), (action) => Math.round(action.getBoundingClientRect().height))
3261+
};
3262+
}));
32243263
expect(tileLayout).toEqual([
32253264
{ height: 142, width: 180 },
32263265
{ height: 142, width: 180 },
@@ -3229,6 +3268,9 @@ test.describe("Workspace Manager V2 bootstrap", () => {
32293268
{ height: 142, width: 180 },
32303269
{ height: 142, width: 180 }
32313270
]);
3271+
expect([...new Set(tileActionLayout.map((entry) => entry.actionBottomGap))]).toHaveLength(1);
3272+
expect(tileActionLayout.every((entry) => entry.actionHeight === 24)).toBe(true);
3273+
expect(tileActionLayout.every((entry) => entry.chipHeights.every((height) => height === 22))).toBe(true);
32323274
await expect(page.locator("#statusLog")).toHaveValue(/OK Boundary contract: game\.gameData is runtime data; game\.workspace is editor\/tool state\. Runtime ignores game\.workspace; tools may read game\.gameData, write game\.workspace, and update game\.gameData only through explicit validated apply\/build\/export actions\./);
32333275
await expect(page.locator("#statusLog")).toHaveValue(/OK Hydrated workspace session for asset-manager-v2, palette-manager-v2, preview-generator-v2, text2speech-V2, session-inspector-v2\./);
32343276
await expect(page.locator("#statusLog")).toHaveValue(/INFO Skipped workspace session hydration for templates-v2: starter\/dev-only tool is not enabled by the selected game workspace config\./);

tests/runtime/GamesIndexWorkspaceManagerOpen.test.mjs

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -373,7 +373,6 @@ function readExpectedMetadataSets() {
373373
const tileMapEntries = manifest?.tools?.["tile-map-editor"]?.maps;
374374
const parallaxEntries = manifest?.tools?.["parallax-editor"]?.parallaxLevels;
375375
const vectorEntries = manifest?.tools?.["svg-asset-studio"]?.vectors;
376-
const assetBrowserEntries = manifest?.tools?.["asset-browser"]?.assets;
377376

378377
const countEntries = (value) => {
379378
if (Array.isArray(value)) {
@@ -390,7 +389,6 @@ function readExpectedMetadataSets() {
390389
|| countEntries(tileMapEntries) > 0
391390
|| countEntries(parallaxEntries) > 0
392391
|| countEntries(vectorEntries) > 0
393-
|| countEntries(assetBrowserEntries) > 0
394392
);
395393
hasManifestVectors = countEntries(vectorEntries) > 0;
396394
const firstSkin = hasManifestSkin ? skins[0] : null;

tests/runtime/SampleStandaloneToolDataFlow.test.mjs

Lines changed: 0 additions & 94 deletions
Original file line numberDiff line numberDiff line change
@@ -657,32 +657,6 @@ function findPresetFilePathForSample(sampleId, toolId) {
657657
return "";
658658
}
659659

660-
async function runTargetedAssetBrowserAssertion(page, url) {
661-
await page.navigate(url);
662-
let status = null;
663-
const started = Date.now();
664-
while ((Date.now() - started) < 9000) {
665-
status = await page.evaluate(`(() => {
666-
const statusText = String(document.getElementById("importStatusText")?.textContent || "").trim();
667-
const selectedCategory = String(document.getElementById("importCategorySelect")?.value || "").trim();
668-
const selectedDestination = String(document.getElementById("importDestinationSelect")?.value || "").trim();
669-
const destinationOptionCount = Number(document.getElementById("importDestinationSelect")?.options?.length || 0);
670-
return { statusText, selectedCategory, selectedDestination, destinationOptionCount };
671-
})()`);
672-
if (/Loaded preset/i.test(status.statusText) || /Preset load failed/i.test(status.statusText)) {
673-
break;
674-
}
675-
await wait(150);
676-
}
677-
678-
assert.match(status.statusText, /Loaded preset/i, "Asset Browser did not report preset load.");
679-
assert.doesNotMatch(status.statusText, /Preset load failed/i, "Asset Browser reported preset load failure.");
680-
assert.ok(status.selectedCategory, "Asset Browser selected category is empty.");
681-
assert.equal(status.selectedDestination, "", "Asset Browser destination should require explicit action-time selection.");
682-
assert.ok(status.destinationOptionCount > 1, "Asset Browser destination options were not populated.");
683-
return status;
684-
}
685-
686660
async function runTargetedAssetPipelineAssertion(page, url, expectedGameId) {
687661
await page.navigate(url);
688662
let status = null;
@@ -771,9 +745,6 @@ function extractPaletteFromPresetPayload(rawPreset) {
771745

772746
function buildTargetedCases(roundtripRows, toolMap) {
773747
const specs = [
774-
{ sampleId: "0204", toolId: "asset-browser" },
775-
{ sampleId: "1413", toolId: "asset-browser" },
776-
{ sampleId: "1505", toolId: "asset-browser" },
777748
{ sampleId: "0510", toolId: "asset-pipeline" },
778749
{ sampleId: "1413", toolId: "asset-pipeline" },
779750
{ sampleId: "1417", toolId: "asset-pipeline" },
@@ -819,9 +790,6 @@ function buildGenericFailureCloseoutCases(roundtripRows, toolMap) {
819790
{ sampleId: "0210", toolId: "physics-sandbox" },
820791
{ sampleId: "0303", toolId: "physics-sandbox" },
821792
{ sampleId: "1606", toolId: "physics-sandbox" },
822-
{ sampleId: "0221", toolId: "tile-model-converter" },
823-
{ sampleId: "0305", toolId: "tile-model-converter" },
824-
{ sampleId: "1209", toolId: "tile-model-converter" },
825793
{ sampleId: "0221", toolId: "3d-json-payload" },
826794
{ sampleId: "0305", toolId: "3d-json-payload" },
827795
{ sampleId: "1208", toolId: "3d-json-payload" },
@@ -950,54 +918,6 @@ async function runPhysicsSandboxContractAssertion(page, url, expectedBody) {
950918
return status;
951919
}
952920

953-
async function runTileModelConverterContractAssertion(page, url, expectedCandidate, expectedConversion) {
954-
await page.navigate(url);
955-
let status = null;
956-
const started = Date.now();
957-
while ((Date.now() - started) < 9000) {
958-
status = await page.evaluate(`(() => {
959-
const statusText = String(document.getElementById("converterStatus")?.textContent || "").trim();
960-
const inputText = String(document.getElementById("converterInput")?.value || "").trim();
961-
let parsed = null;
962-
try {
963-
parsed = inputText ? JSON.parse(inputText) : null;
964-
} catch {
965-
parsed = null;
966-
}
967-
const candidateKeys = parsed?.candidate && typeof parsed.candidate === "object" ? Object.keys(parsed.candidate) : [];
968-
const conversionKeys = parsed?.conversion && typeof parsed.conversion === "object" ? Object.keys(parsed.conversion) : [];
969-
return {
970-
statusText,
971-
parsedCandidate: parsed?.candidate || null,
972-
parsedConversion: parsed?.conversion || null,
973-
candidateCount: candidateKeys.length,
974-
conversionCount: conversionKeys.length
975-
};
976-
})()`);
977-
if (
978-
/Preset load failed/i.test(status.statusText)
979-
|| (status.candidateCount > 0 && status.conversionCount > 0)
980-
) {
981-
break;
982-
}
983-
await wait(150);
984-
}
985-
assert.doesNotMatch(status.statusText, /Preset load failed/i, "Tile Model Converter reported preset load failure.");
986-
assert.ok(status.candidateCount > 0, "Tile Model Converter candidate payload is empty.");
987-
assert.ok(status.conversionCount > 0, "Tile Model Converter conversion payload is empty.");
988-
assert.equal(
989-
JSON.stringify(status.parsedCandidate),
990-
JSON.stringify(expectedCandidate),
991-
"Tile Model Converter candidate payload mismatch."
992-
);
993-
assert.equal(
994-
JSON.stringify(status.parsedConversion),
995-
JSON.stringify(expectedConversion),
996-
"Tile Model Converter conversion payload mismatch."
997-
);
998-
return status;
999-
}
1000-
1001921
async function runJsonNormalizerContractAssertion(page, url, expectedPointCount, expectedSegmentCount) {
1002922
await page.navigate(url);
1003923
let status = null;
@@ -1193,15 +1113,6 @@ export async function run() {
11931113
genericContractResults.push({ sampleId: testCase.sampleId, toolId: testCase.toolId, ...result });
11941114
continue;
11951115
}
1196-
if (testCase.toolId === "tile-model-converter") {
1197-
const expectedCandidate = testCase.presetPayload?.config?.candidate;
1198-
const expectedConversion = testCase.presetPayload?.config?.conversion;
1199-
assert.ok(expectedCandidate && typeof expectedCandidate === "object", `Missing expected converter candidate in ${toPosixPath(path.relative(repoRoot, testCase.presetFilePath))}.`);
1200-
assert.ok(expectedConversion && typeof expectedConversion === "object", `Missing expected converter conversion in ${toPosixPath(path.relative(repoRoot, testCase.presetFilePath))}.`);
1201-
const result = await runTileModelConverterContractAssertion(page, url, expectedCandidate, expectedConversion);
1202-
genericContractResults.push({ sampleId: testCase.sampleId, toolId: testCase.toolId, ...result });
1203-
continue;
1204-
}
12051116
if (testCase.toolId === "3d-json-payload") {
12061117
const expectedPointCount = Array.isArray(testCase.presetPayload?.config?.mapPayload?.points)
12071118
? testCase.presetPayload.config.mapPayload.points.length
@@ -1250,11 +1161,6 @@ export async function run() {
12501161

12511162
for (const testCase of targetedCases) {
12521163
const url = buildStandaloneToolUrl(baseUrl, testCase.tool.entryPoint, testCase.row);
1253-
if (testCase.toolId === "asset-browser") {
1254-
const result = await runTargetedAssetBrowserAssertion(page, url);
1255-
targetedResults.push({ sampleId: testCase.sampleId, toolId: testCase.toolId, ...result });
1256-
continue;
1257-
}
12581164
if (testCase.toolId === "asset-pipeline") {
12591165
const expectedGameId = String(testCase.presetPayload?.config?.pipelinePayload?.gameId || "").trim();
12601166
assert.ok(expectedGameId, `Missing expected pipeline gameId in ${toPosixPath(path.relative(repoRoot, testCase.presetFilePath))}.`);

tests/tools/AssetUsageIntegration.test.mjs

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -39,22 +39,20 @@ export async function run() {
3939

4040
try {
4141
const actions = getSharedShellActions("sprite-editor", "tool");
42-
assert.equal(actions.length, 4);
42+
assert.equal(actions.length, 2);
4343
assert.deepEqual(
4444
actions.map((entry) => entry.label),
4545
[
46-
SHARED_ACTION_LABELS.browseAssets,
47-
SHARED_ACTION_LABELS.importAssets,
4846
SHARED_ACTION_LABELS.browsePalettes,
4947
SHARED_ACTION_LABELS.managePalettes
5048
]
5149
);
5250
assert.equal(
5351
actions[0].href,
54-
"../Asset Browser/index.html?view=browse&sourceToolId=sprite-editor"
52+
"../palette-manager-v2/index.html?view=browse&sourceToolId=sprite-editor"
5553
);
5654
assert.equal(
57-
actions[3].href,
55+
actions[1].href,
5856
"../palette-manager-v2/index.html?view=manage&sourceToolId=sprite-editor"
5957
);
6058

0 commit comments

Comments
 (0)