Skip to content

Commit f1581f9

Browse files
author
DavidQ
committed
Clean workspace status messages preview state and Text to Speech scroll behavior - PR_26130_031-workspace-status-preview-and-text2speech-scroll-cleanup
1 parent a3cc6d2 commit f1581f9

14 files changed

Lines changed: 286 additions & 82 deletions
Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
# PR_26130_031-workspace-status-preview-and-text2speech-scroll-cleanup
2+
3+
## Summary
4+
- Moved Workspace Manager V2 Active Game summary/status messaging into the existing Status log and removed the `activeGameSummary` paragraph from the Active Game panel.
5+
- Constrained the Active Game panel to content height and reduced the Workspace JSON textarea height from 260px to 240px.
6+
- Updated Preview Generator V2 workspace tile detail text to show only `Preview Found` or `Preview Not Found` based on `assets/images/preview.svg` under the selected game root.
7+
- Consolidated shared palette action labels to the single `Palette Manager` source label and removed the deprecated `Browse Palettes`/`Manage Palettes` shared action split.
8+
- Adjusted Text to Speech V2 page height rules so the page scrollbar appears only when content exceeds the viewport while preserving internal panel scrolling.
9+
10+
## Scope Notes
11+
- No `start_of_day` files changed.
12+
- No Workspace Manager V2 schema contracts were changed.
13+
- No Preview Generator V2 write behavior was changed; this PR only updates the workspace tile/status display.
14+
- Full samples smoke test was intentionally not run.
15+
16+
## Playwright Impacted
17+
Yes.
18+
19+
Validated behavior:
20+
- `activeGameSummary` no longer exists in Workspace Manager V2.
21+
- Active game selection/discovery messages are written to `#statusLog`.
22+
- Active Game panel layout shrinks to content and Workspace JSON height is reduced.
23+
- Preview Generator V2 tile displays `Preview Found` or `Preview Not Found` and does not display `Waiting for manifest`.
24+
- `SHARED_ACTION_LABELS` exposes `Palette Manager` as the single shared action label.
25+
- Text to Speech V2 page scroll is conditional: no page scrollbar when content fits, page scrollbar appears when content is forced past the viewport.
26+
27+
Expected pass behavior:
28+
- `npm run test:workspace-v2` passes all Workspace Manager V2 tests.
29+
- Preview Generator V2 tile detail is preview-existence specific and does not duplicate manifest/general state text.
30+
- Text to Speech V2 keeps panel-level scrollbars while allowing page-level scrolling only when needed.
31+
32+
Expected fail behavior:
33+
- Reintroducing `#activeGameSummary` fails Playwright coverage.
34+
- Reintroducing `Waiting for manifest`, `Browse Palettes`, or multiple shared palette action labels fails updated assertions.
35+
- Regressing Text to Speech V2 page overflow behavior fails the scrollbar coverage.
36+
37+
## Validation
38+
- PASS: `npm run test:workspace-v2` -> 37 passed.
39+
- PASS: Targeted rerun for `loads Text to Speech V2 from URL JSON` during layout fix -> 1 passed.
40+
- PASS: `git diff --check` -> no whitespace errors; CRLF conversion warnings only.
41+
- PASS: Playwright V8 coverage report generated at `docs/dev/reports/playwright_v8_coverage_report.txt`.
42+
43+
Coverage highlights for changed runtime JS:
44+
- `(86%) tools/workspace-manager-v2/js/WorkspaceManagerV2App.js`
45+
- `(91%) tools/workspace-manager-v2/js/services/WorkspaceManagerV2ContextService.js`
46+
- `(93%) tools/workspace-manager-v2/js/controls/GameSelectorControl.js`
47+
- `(93%) tools/workspace-manager-v2/js/controls/ToolTilesControl.js`
48+
- `(100%) tools/workspace-manager-v2/js/bootstrap.js`
49+
- `(32%) tools/shared/assetUsageIntegration.js`
50+
51+
## Full Samples Smoke Test
52+
Skipped. This PR is limited to Workspace Manager V2 status/tile presentation, shared palette action labels, and Text to Speech V2 scroll CSS; the required targeted Workspace V2 Playwright suite was run instead.
53+
54+
## Manual Validation
55+
1. Open Workspace Manager V2, confirm Active Game has only the game dropdown and messages appear in Status.
56+
2. Select a game and confirm Preview Generator V2 tile shows `Preview Found` only when `assets/images/preview.svg` exists, otherwise `Preview Not Found`.
57+
3. Open Text to Speech V2 at a tall viewport and confirm the page has no scrollbar until content exceeds the viewport.
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_031-workspace-status-preview-and-text2speech-scroll-cleanup_delta.zip`

tests/playwright/tools/WorkspaceManagerV2.spec.mjs

Lines changed: 108 additions & 20 deletions
Large diffs are not rendered by default.

tests/tools/AssetUsageIntegration.test.mjs

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

4040
try {
4141
const actions = getSharedShellActions("sprite-editor", "tool");
42-
assert.equal(actions.length, 2);
42+
assert.equal(actions.length, 1);
4343
assert.deepEqual(
4444
actions.map((entry) => entry.label),
4545
[
46-
SHARED_ACTION_LABELS.browsePalettes,
47-
SHARED_ACTION_LABELS.managePalettes
46+
SHARED_ACTION_LABELS.paletteManager
4847
]
4948
);
5049
assert.equal(
5150
actions[0].href,
52-
"../palette-manager-v2/index.html?view=browse&sourceToolId=sprite-editor"
53-
);
54-
assert.equal(
55-
actions[1].href,
56-
"../palette-manager-v2/index.html?view=manage&sourceToolId=sprite-editor"
51+
"../palette-manager-v2/index.html?sourceToolId=sprite-editor"
5752
);
5853

5954
const validAsset = createAssetHandoff({

tests/tools/ToolEntryLaunchContract.test.mjs

Lines changed: 3 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -33,21 +33,16 @@ export async function run() {
3333
try {
3434
FIRST_CLASS_TOOL_INDEXES.forEach(({ toolId }) => {
3535
const actions = getSharedShellActions(toolId, "tool");
36-
assert.equal(actions.length, 2);
36+
assert.equal(actions.length, 1);
3737
assert.deepEqual(
3838
actions.map((action) => action.label),
3939
[
40-
SHARED_ACTION_LABELS.browsePalettes,
41-
SHARED_ACTION_LABELS.managePalettes
40+
SHARED_ACTION_LABELS.paletteManager
4241
]
4342
);
4443
assert.equal(
4544
actions[0].href,
46-
`../palette-manager-v2/index.html?view=browse&sourceToolId=${toolId}`
47-
);
48-
assert.equal(
49-
actions[1].href,
50-
`../palette-manager-v2/index.html?view=manage&sourceToolId=${toolId}`
45+
`../palette-manager-v2/index.html?sourceToolId=${toolId}`
5146
);
5247
});
5348
} finally {

tools/palette-manager-v2/how_to_use.html

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ <h2>Tags</h2>
2828
<p>Tags lists existing user palette tags. Click a tag to toggle it on the selected swatch, or enter a new tag name and add it to the selected swatch. Tags are stored in lowercase.</p>
2929
</section>
3030
<section class="card">
31-
<h2>Browse Palettes</h2>
31+
<h2>Palette Sources</h2>
3232
<p>Choose Crayola, W3C, or JavaScript, search the browse-only list, and use the red tack to copy a swatch into the user palette.</p>
3333
</section>
3434
<section class="card">

tools/shared/assetUsageIntegration.js

Lines changed: 5 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,7 @@ export const SHARED_ASSET_HANDOFF_EVENT = "toolboxaid.shared.assetHandoff.change
66
export const SHARED_PALETTE_HANDOFF_EVENT = "toolboxaid.shared.paletteHandoff.changed";
77

88
export const SHARED_ACTION_LABELS = Object.freeze({
9-
browsePalettes: "Browse Palettes",
10-
managePalettes: "Manage Palettes"
9+
paletteManager: "Palette Manager"
1110
});
1211

1312
function sanitizeText(value) {
@@ -158,21 +157,13 @@ export function getSharedToolHref(targetToolId, pageMode = "tool", options = {})
158157
}
159158

160159
export function getSharedShellActions(currentToolId, pageMode = "tool") {
161-
const { view } = getSharedLaunchContext();
162160
return [
163161
{
164-
id: "browse-palettes",
162+
id: "palette-manager",
165163
targetToolId: "palette-manager-v2",
166-
label: SHARED_ACTION_LABELS.browsePalettes,
167-
href: getSharedToolHref("palette-manager-v2", pageMode, { view: "browse", sourceToolId: currentToolId }),
168-
current: currentToolId === "palette-manager-v2" && view !== "manage"
169-
},
170-
{
171-
id: "manage-palettes",
172-
targetToolId: "palette-manager-v2",
173-
label: SHARED_ACTION_LABELS.managePalettes,
174-
href: getSharedToolHref("palette-manager-v2", pageMode, { view: "manage", sourceToolId: currentToolId }),
175-
current: currentToolId === "palette-manager-v2" && view === "manage"
164+
label: SHARED_ACTION_LABELS.paletteManager,
165+
href: getSharedToolHref("palette-manager-v2", pageMode, { sourceToolId: currentToolId }),
166+
current: currentToolId === "palette-manager-v2"
176167
}
177168
];
178169
}

tools/text2speech-V2/styles/text2speech-V2.css

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -128,8 +128,9 @@ body.tools-platform-tool-page[data-tool-id="text2speech-V2"] > .palette-manager-
128128
grid-template-columns: minmax(260px, 0.85fr) minmax(320px, 1.2fr) minmax(260px, 0.85fr);
129129
align-items: stretch;
130130
gap: 16px;
131-
height: min(720px, calc(100vh - 190px));
132-
min-height: 620px;
131+
height: clamp(500px, calc(100vh - 565px), 720px);
132+
height: clamp(500px, calc(100dvh - 565px), 720px);
133+
min-height: 0;
133134
width: min(1180px, calc(100% - 32px));
134135
margin: 0 auto 28px;
135136
}

tools/workspace-manager-v2/index.html

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,7 @@ <h2 class="tools-platform-frame__eyebrow">Games-only launch context</h2>
6363
</div>
6464
</section>
6565

66-
<section class="accordion-v2 workspace-manager-v2__accordion is-open" data-accordion-v2-open="true">
66+
<section class="accordion-v2 workspace-manager-v2__accordion workspace-manager-v2__accordion--active-game is-open" data-accordion-v2-open="true">
6767
<button class="accordion-v2__header" type="button" aria-expanded="true" aria-controls="activeGameContent">
6868
<span>Active Game</span>
6969
<span class="accordion-v2__icon" aria-hidden="true">+</span>
@@ -73,7 +73,6 @@ <h2 class="tools-platform-frame__eyebrow">Games-only launch context</h2>
7373
<span>Game</span>
7474
<select id="activeGameSelect"></select>
7575
</label>
76-
<p id="activeGameSummary" class="workspace-manager-v2__hint">Pick a repo folder to discover schema-valid game manifests.</p>
7776
</div>
7877
</section>
7978
</aside>

tools/workspace-manager-v2/js/WorkspaceManagerV2App.js

Lines changed: 15 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -242,7 +242,7 @@
242242
sourceBindingState: "invalid"
243243
});
244244
this.updateRepoRuntimeBinding(invalidBinding);
245-
this.applyContextResult({
245+
await this.applyContextResult({
246246
assetCount: metrics.assetCount,
247247
context: restoredToolState.context,
248248
game: restoredToolState.game,
@@ -261,7 +261,7 @@
261261
sourceBindingState: "bound"
262262
});
263263
this.updateRepoRuntimeBinding(reboundBinding);
264-
this.applyContextResult({
264+
await this.applyContextResult({
265265
assetCount: metrics.assetCount,
266266
context: restoredToolState.context,
267267
game: sourceBinding.game,
@@ -319,7 +319,7 @@
319319
return;
320320
}
321321

322-
this.applyContextResult(result);
322+
await this.applyContextResult(result);
323323
if (result.assetWarning) {
324324
this.statusLog.info(`Warning: ${result.assetWarning}`);
325325
}
@@ -432,7 +432,7 @@
432432
this.repoDestination.setRepoDestinationDisplayName(repoReferenceResult.reference.displayName);
433433
this.gameSelector.setValue(restoredResult.game.id, restoredResult.game.name);
434434
const requiresRepoHandle = !this.activeRepoHandle;
435-
this.applyContextResult(restoredResult, { requiresRepoHandle });
435+
await this.applyContextResult(restoredResult, { requiresRepoHandle });
436436
if (restoredResult.assetWarning) {
437437
this.statusLog.info(`Warning: ${restoredResult.assetWarning}`);
438438
}
@@ -465,7 +465,7 @@
465465
this.statusLog.ok(`Restored ${restoredResult.game.name} workspace from session context ${restoredResult.hostContextId}.`);
466466
}
467467

468-
applyContextResult(result, { requiresRepoHandle = false } = {}) {
468+
async applyContextResult(result, { requiresRepoHandle = false } = {}) {
469469
const tools = this.contextService.workspaceLaunchableTools();
470470
const runtimeBinding = this.runtimeBindingMetadata({
471471
bindingSource: requiresRepoHandle
@@ -500,6 +500,10 @@
500500
const textToSpeechCount = Number.isInteger(textToSpeechSummary.speechQueueCount)
501501
? textToSpeechSummary.speechQueueCount
502502
: 0;
503+
const previewStatus = await this.contextService.previewAssetStatusForGame({
504+
game: result.game,
505+
repoHandle: requiresRepoHandle ? null : this.activeRepoHandle
506+
});
503507
this.activeContext = sessionRefresh.context;
504508
this.activeGame = result.game;
505509
this.activeHostContextId = result.hostContextId || null;
@@ -522,6 +526,7 @@
522526
enabledToolIds: hydration.ok ? hydration.hydratedToolIds : [],
523527
manifestStatus: this.activeToolStateRequiresRepoHandle ? "Repo folder required" : "Schema-valid manifest",
524528
paletteSwatchCount,
529+
previewStatus: previewStatus.status,
525530
textToSpeechCount
526531
});
527532
this.syncLifecycleControls();
@@ -591,7 +596,7 @@
591596
}
592597
}
593598
const metrics = this.contextSummaryMetrics(this.activeContext);
594-
this.applyContextResult({
599+
await this.applyContextResult({
595600
assetCount: metrics.assetCount,
596601
context: this.activeContext,
597602
game,
@@ -721,7 +726,7 @@
721726
this.updateRepoRuntimeBinding(reboundBinding);
722727
this.statusLog.info(`Save source rebound to ${sourceBinding.source} for ${result.game.id}.`);
723728
this.statusLog.ok(`Runtime handle rebound: ${this.runtimeBindingDetails(reboundBinding)}.`);
724-
this.applyContextResult({ ...result, game: sourceBinding.game });
729+
await this.applyContextResult({ ...result, game: sourceBinding.game });
725730
if (result.assetWarning) {
726731
this.statusLog.info(`Warning: ${result.assetWarning}`);
727732
}
@@ -736,7 +741,7 @@
736741
return { ok: false, message: refreshedValidation.message };
737742
}
738743
const metrics = this.contextSummaryMetrics(sessionRefresh.context);
739-
this.applyContextResult({
744+
await this.applyContextResult({
740745
assetCount: metrics.assetCount,
741746
context: sessionRefresh.context,
742747
game: this.activeGame,
@@ -829,7 +834,7 @@
829834
return;
830835
}
831836
const metrics = this.contextSummaryMetrics(context);
832-
this.applyContextResult({
837+
await this.applyContextResult({
833838
assetCount: metrics.assetCount,
834839
context,
835840
game: this.activeGame,
@@ -957,7 +962,7 @@
957962
}
958963
const hostContextId = this.contextService.persistContext(result.context);
959964
this.gameSelector.setValue(result.game.id, result.game.name);
960-
this.applyContextResult({ ...result, hostContextId });
965+
await this.applyContextResult({ ...result, hostContextId });
961966
if (result.assetWarning) {
962967
this.statusLog.info(`Warning: ${result.assetWarning}`);
963968
}

tools/workspace-manager-v2/js/bootstrap.js

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -17,12 +17,18 @@ function requireElement(selector) {
1717
}
1818

1919
window.addEventListener("DOMContentLoaded", () => {
20+
const statusLog = new StatusLogControl({
21+
clearButton: requireElement("#clearStatusButton"),
22+
log: requireElement("#statusLog")
23+
});
2024
const app = new WorkspaceManagerV2App({
2125
accordions: Array.from(document.querySelectorAll(".accordion-v2"), (section) => new AccordionSection(section)),
2226
contextService: new WorkspaceManagerV2ContextService(),
2327
gameSelector: new GameSelectorControl({
24-
select: requireElement("#activeGameSelect"),
25-
summary: requireElement("#activeGameSummary")
28+
onSummary: (message) => {
29+
statusLog.info(message);
30+
},
31+
select: requireElement("#activeGameSelect")
2632
}),
2733
menu: new ManifestMenuControl({
2834
cancelButton: requireElement("#cancelWorkspaceButton"),
@@ -34,10 +40,7 @@ window.addEventListener("DOMContentLoaded", () => {
3440
pickRepoButton: requireElement("#pickRepoBtn"),
3541
repoSelectedValue: requireElement("#repoSelectedValue")
3642
}),
37-
statusLog: new StatusLogControl({
38-
clearButton: requireElement("#clearStatusButton"),
39-
log: requireElement("#statusLog")
40-
}),
43+
statusLog,
4144
summary: new WorkspaceSummaryControl({
4245
copyButton: requireElement("#copyWorkspaceJsonButton"),
4346
contextOutput: requireElement("#workspaceContextOutput")

0 commit comments

Comments
 (0)