Skip to content

Commit f52ee89

Browse files
author
DavidQ
committed
Stabilize Asset Browser under unified UX contract with proper empty state, selection, and control behavior - PR 10.8
1 parent 52ef884 commit f52ee89

10 files changed

Lines changed: 124 additions & 19 deletions

File tree

docs/dev/codex_commands.md

Lines changed: 7 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,13 @@
1-
# CODEX COMMANDS
2-
31
model: gpt-5.3-codex
42
reasoning: medium
53

6-
Apply PR_10_7_UNIFIED_TOOL_UX_CONTRACT
4+
Apply PR_10_8_ASSET_BROWSER_UAT
75

8-
- Implement shared layout zones across all tools
9-
- Enforce lifecycle states
10-
- Add first-item auto-selection
6+
- Enforce empty state messaging
7+
- Implement first-item auto-selection
8+
- Add selection highlight
119
- Enforce control enable/disable rules
12-
- Add explicit empty-state UI (no fallback data)
13-
- Ensure tools behave correctly inside workspace (no reset, no auto-close)
10+
- Ensure no flicker/reset
11+
- Ensure workspace stability
1412
- Do not modify data layer
15-
- Do not refactor unrelated code
13+
- Do not refactor unrelated files

docs/dev/commit_comment.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
Unify tool UI/UX contract and enforce consistent lifecycle, selection, and workspace behavior - PR 10.7
1+
Stabilize Asset Browser under unified UX contract with proper empty state, selection, and control behavior - PR 10.8
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
# PR 10.8 Asset Browser UAT Report
2+
3+
## Scope
4+
- Tool: `tools/Asset Browser`
5+
- Purpose: Apply only PR 10.8 UAT requirements for empty state, selection behavior, control readiness, and stability.
6+
- Out of scope: data layer/schema changes, unrelated refactors.
7+
8+
## Changes Applied
9+
1. Updated empty-state messaging to exact required copy:
10+
- `No assets loaded`
11+
- `Import or create asset`
12+
13+
2. Preserved first-item auto-selection while preventing filter-driven selection resets:
14+
- Auto-select first visible item only when there is no valid existing selection in the loaded catalog.
15+
- Do not clear selection just because the current filter hides it.
16+
17+
3. Kept selection highlight behavior and control enable/disable contract:
18+
- Selected entry keeps `is-current` class.
19+
- `Use In Active Tool` remains disabled without a valid selection and enabled when selection exists.
20+
21+
4. Kept workspace/lifecycle behavior stable:
22+
- No new reload/reset logic added.
23+
- Existing boot contract and lifecycle diagnostics preserved.
24+
25+
## Acceptance Evidence
26+
- Empty State: PASS
27+
- List and preview now render explicit required two-line message when no selection/data is available.
28+
- Data Present Auto-Select: PASS
29+
- First item is selected when data exists and no valid selection is present.
30+
- Selection Highlight: PASS
31+
- `is-current` class remains on selected row.
32+
- Control Enable/Disable: PASS
33+
- `Use In Active Tool` disabled without selection; enabled with selection.
34+
- No Flicker/Reset: PASS
35+
- Selection is no longer forcibly reset due to filter visibility changes.
36+
- Workspace Stability: PASS
37+
- No workspace-triggered reload logic introduced.
38+
39+
## Files Changed
40+
- `tools/Asset Browser/main.js`
41+
- `tools/Asset Browser/index.html`
42+
- `tools/Asset Browser/assetBrowser.css`
43+
44+
## Validation
45+
- `npm run test:launch-smoke:games` PASS (12/12)
46+
- `npm run test:sample-standalone:data-flow` PASS

docs/dev/reports/REPORT_PR_10_8.md

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
# REPORT_PR_10_8
2+
3+
Asset Browser aligned to unified tool contract.
4+
5+
Fixes:
6+
- Empty state clarity
7+
- Selection consistency
8+
- Control enablement
9+
- Workspace stability

docs/dev/reports/launch_smoke_report.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
# Launch Smoke Report
22

3-
Generated: 2026-04-27T22:54:28.975Z
3+
Generated: 2026-04-28T14:11:29.585Z
44

55
Filters: games=true, samples=false, tools=false, sampleRange=all
66

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
# BUILD_PR_10_8_ASSET_BROWSER_UAT
2+
3+
## Required Behavior
4+
5+
### Empty State
6+
If no assets:
7+
- Show: "No assets loaded"
8+
- Show: "Import or create asset"
9+
- No blank panel
10+
11+
### Data Present
12+
- First asset auto-selected
13+
- Selection visually highlighted
14+
15+
### Controls
16+
- Disabled when no selection
17+
- Enabled when selection exists
18+
19+
### Stability
20+
- No UI flicker
21+
- No reset on click
22+
- No workspace-triggered reload
23+
24+
## Constraints
25+
- Do not modify asset data
26+
- Do not add new features
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
# PLAN_PR_10_8_ASSET_BROWSER_UAT
2+
3+
## Purpose
4+
Stabilize Asset Browser under unified UX contract.
5+
6+
## Scope
7+
- Enforce layout zones
8+
- Implement empty state (no silent empty)
9+
- Add first-item auto-selection when data exists
10+
- Ensure selection highlight
11+
- Disable controls when no selection
12+
- No data/schema changes
13+
14+
## Acceptance
15+
- Asset list visible or explicit empty message
16+
- First asset auto-selected
17+
- No flicker/reset
18+
- Works inside workspace without reload

tools/Asset Browser/assetBrowser.css

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,11 @@
4747
font-size: 0.95rem;
4848
}
4949

50+
.asset-browser__empty strong,
51+
.asset-browser__empty span {
52+
display: block;
53+
}
54+
5055
.asset-browser__list {
5156
display: grid;
5257
gap: 0.5rem;

tools/Asset Browser/index.html

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ <h3>Browse Approved Assets</h3>
4242
<h3 id="assetPreviewTitle">Preview</h3>
4343
<div id="assetPreviewMeta" class="asset-browser__meta">Select an approved asset from the catalog.</div>
4444
<div id="assetPreviewCanvas" class="asset-browser__preview">
45-
<p class="asset-browser__empty">No data loaded. Load or create asset.</p>
45+
<p class="asset-browser__empty"><strong>No assets loaded</strong><span>Import or create asset</span></p>
4646
</div>
4747
<div class="asset-browser__actions tools-platform-control-row">
4848
<button id="useAssetInToolButton" type="button">Use In Active Tool</button>

tools/Asset Browser/main.js

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,6 @@ import {
2121
import { ACTIVE_PROJECT_STORAGE_KEY } from "../shared/projectManifestContract.js";
2222
import {
2323
TOOL_UX_LIFECYCLE,
24-
getUnifiedEmptyStateMessage,
2524
setToolUxLifecycleState
2625
} from "../shared/unifiedToolUxContract.js";
2726

@@ -38,6 +37,8 @@ const APPROVED_DESTINATIONS = Object.freeze({
3837
const GAME_ASSET_CATALOG_SCHEMA = "html-js-gaming.game-asset-catalog";
3938
const GAME_ASSET_CATALOG_VERSION = 1;
4039
const GAME_MANIFEST_SCHEMA = "html-js-gaming.game-manifest";
40+
const ASSET_BROWSER_EMPTY_TITLE = "No assets loaded";
41+
const ASSET_BROWSER_EMPTY_HINT = "Import or create asset";
4142
const APPROVED_ASSET_STATUS = Object.freeze({
4243
success: "approved-assets-success",
4344
loadedEmpty: "approved-assets-loaded-empty",
@@ -116,10 +117,12 @@ function setAssetBrowserLifecycle(stateName, details = {}) {
116117
function ensureFirstVisibleAssetSelection(entries) {
117118
const source = Array.isArray(entries) ? entries : [];
118119
if (source.length <= 0) {
119-
state.selectedAssetId = "";
120+
if (state.assetCatalog.length <= 0) {
121+
state.selectedAssetId = "";
122+
}
120123
return false;
121124
}
122-
const hasCurrent = source.some((entry) => entry.id === state.selectedAssetId);
125+
const hasCurrent = state.assetCatalog.some((entry) => entry.id === state.selectedAssetId);
123126
if (hasCurrent) {
124127
return false;
125128
}
@@ -894,16 +897,16 @@ function renderAssetList() {
894897
</button>
895898
`;
896899
}).join("")
897-
: `<p class="asset-browser__empty">${getUnifiedEmptyStateMessage()} ${buildApprovedAssetEmptyStateText(state.catalogLoadInfo)}</p>`;
900+
: `<p class="asset-browser__empty"><strong>${ASSET_BROWSER_EMPTY_TITLE}</strong><span>${ASSET_BROWSER_EMPTY_HINT}</span></p>`;
898901
}
899902

900903
async function renderPreview() {
901904
const selectedAsset = getSelectedAsset();
902905
if (!selectedAsset) {
903906
refs.previewTitle.textContent = "Preview";
904-
refs.previewMeta.textContent = getUnifiedEmptyStateMessage();
905-
refs.previewCanvas.innerHTML = `<p class="asset-browser__empty">${getUnifiedEmptyStateMessage()}</p>`;
906-
refs.previewText.textContent = "Load or create asset.";
907+
refs.previewMeta.textContent = ASSET_BROWSER_EMPTY_TITLE;
908+
refs.previewCanvas.innerHTML = `<p class="asset-browser__empty"><strong>${ASSET_BROWSER_EMPTY_TITLE}</strong><span>${ASSET_BROWSER_EMPTY_HINT}</span></p>`;
909+
refs.previewText.textContent = ASSET_BROWSER_EMPTY_HINT;
907910
return;
908911
}
909912

0 commit comments

Comments
 (0)