Skip to content

Commit 50028e2

Browse files
committed
Polish Controls device refresh profile edit flow and gold action highlight - PR_26161_030-controls-device-refresh-profile-polish
1 parent f424497 commit 50028e2

9 files changed

Lines changed: 295 additions & 556 deletions

File tree

assets/theme-v2/css/typography.css

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -131,6 +131,10 @@ dd {
131131
padding-block: var(--space-6)
132132
}
133133

134+
.text-gold {
135+
color: var(--gold)
136+
}
137+
134138
.lede {
135139
color: var(--muted);
136140
font-size: var(--font-size-2xl);
Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
1+
assets/theme-v2/css/typography.css
12
docs_build/dev/reports/codex_changed_files.txt
23
docs_build/dev/reports/codex_review.diff
3-
docs_build/dev/reports/controls-controller-profile-edit-mode-report.md
4+
docs_build/dev/reports/controls-device-refresh-profile-polish-report.md
45
docs_build/dev/reports/coverage_changed_js_guardrail.txt
56
docs_build/dev/reports/playwright_v8_coverage_report.txt
67
tests/playwright/tools/InputMappingV2Tool.spec.mjs
78
toolbox/controls/controls.js
9+
toolbox/controls/index.html

docs_build/dev/reports/codex_review.diff

Lines changed: 178 additions & 544 deletions
Large diffs are not rendered by default.
Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
# PR_26161_030 Controls Device Refresh Profile Polish Report
2+
3+
## Scope
4+
- Moved Refresh Devices into Controller Profile next to Device Type.
5+
- Added creator-facing Devices inspector guidance.
6+
- Updated Create Profile From Default so it saves a DB-backed profile and immediately opens that profile in edit mode.
7+
- Changed controller input edit-mode identification to Theme V2 gold text on the selected Action only.
8+
9+
## Branch Validation
10+
- PASS: current branch verified as `main` before edits.
11+
12+
## Impacted Lane
13+
- Controls / Input Mapping.
14+
15+
## Playwright Impacted
16+
- Yes.
17+
18+
## Validation Performed
19+
- PASS: `node --check toolbox/controls/controls.js`
20+
- PASS: `node --check tests/playwright/tools/InputMappingV2Tool.spec.mjs`
21+
- PASS: `Select-String -Path toolbox/controls/index.html -Pattern '<style',' onclick=',' onchange=',' oninput=',' onsubmit='`
22+
- PASS: `git diff --check`
23+
- PASS: `npx playwright test tests/playwright/tools/InputMappingV2Tool.spec.mjs`
24+
25+
## Manual Validation Steps
26+
- Open Controls and confirm Refresh Devices appears to the left of Controller Profile Device Type.
27+
- Open Inspector > Devices and confirm the guidance reads: `Press a button on the controller, then refresh Device Type.`
28+
- Connect or mock a gamepad, refresh devices, choose the gamepad, then click Create Profile From Default.
29+
- Confirm the DB-backed profile appears immediately in edit mode with generated input/action dropdowns visible.
30+
- Press a controller input while editing and confirm only the selected Action text turns Theme V2 gold.
31+
- Confirm the selected input row does not receive a background, border, or layout highlight.
32+
- Assign profile Actions, save, reload, and confirm assignments persist.
33+
34+
## Skipped Lanes
35+
- Full samples validation skipped by request.
36+
- Broad workspace, engine, auth, production DB, and sample lanes skipped because this PR only changes Controls UI/runtime behavior, one reusable Theme V2 text utility, and targeted Playwright coverage exercises the impacted lane.
37+
38+
## Runtime Engine Behavior
39+
- PASS: no production game runtime or engine behavior changed.
40+
41+
## Theme V2 Styling Note
42+
- PASS: added reusable `.text-gold` in Theme V2 typography because the imported Theme V2 bundle did not provide a text-only gold utility. No page-local CSS, inline styles, tool CSS, background, border, or layout styling was added.
43+
44+
## Requirement Checklist
45+
- PASS: Read `docs_build/dev/PROJECT_INSTRUCTIONS.md` before edits.
46+
- PASS: Verified branch `main` before edits.
47+
- PASS: Continued from PR_26161_029 behavior.
48+
- PASS: Controls status remains Wireframe.
49+
- PASS: Controls data remains DB-backed through the shared DB/mock adapter only.
50+
- PASS: Refresh Devices appears left of Controller Profile > Device Type.
51+
- PASS: Inspector > Devices guidance appears at the top.
52+
- PASS: Create Profile From Default creates a DB-backed controller profile.
53+
- PASS: Create Profile From Default immediately places the newly added profile into edit mode.
54+
- PASS: Generated input/action dropdowns are visible after Create Profile From Default.
55+
- PASS: Controller input press in edit mode identifies the selected Action with Theme V2 gold text only.
56+
- PASS: No background, border, layout, or extra visual effect is added for the selected controller input.
57+
- PASS: Controller profile edit-mode behavior, generated input list, action dropdowns, custom Actions, reset confirmation, Input Mapping accordion, Controller Profile accordion, and DB persistence are preserved.
58+
- PASS: No sample JSON alignment, auth behavior, production game runtime behavior, or unrelated rewrites were added.
59+
- PASS: Theme V2 only; no inline CSS, inline JS, script/style blocks, or inline event handlers were added.
60+
- PASS: Targeted Controls/Input Mapping Playwright validation passed.
61+
- PASS: Playwright V8 coverage report produced for changed runtime JavaScript.

docs_build/dev/reports/coverage_changed_js_guardrail.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ Missing changed runtime JS files are WARN, not FAIL.
66
Source: Playwright/Chromium built-in V8 coverage from the active Playwright run.
77

88
Changed runtime JS files considered:
9-
(94%) toolbox/controls/controls.js - executed lines 1686/1686; executed functions 186/197
9+
(94%) toolbox/controls/controls.js - executed lines 1698/1698; executed functions 187/198
1010

1111
Guardrail warnings:
1212
(100%) none - no changed runtime JS coverage warnings

docs_build/dev/reports/playwright_v8_coverage_report.txt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,14 +17,14 @@ Exercised tool entry points detected:
1717
(59%) Theme V2 Shared JS - exercised 2 runtime JS files
1818

1919
Changed runtime JS files covered:
20-
(94%) toolbox/controls/controls.js - executed lines 1686/1686; executed functions 186/197
20+
(94%) toolbox/controls/controls.js - executed lines 1698/1698; executed functions 187/198
2121

2222
Files with executed line/function counts where available:
2323
(53%) src/engine/api/server-api-client.js - executed lines 159/159; executed functions 10/19
2424
(58%) assets/theme-v2/js/gamefoundry-partials.js - executed lines 603/603; executed functions 30/52
2525
(64%) assets/theme-v2/js/tool-display-mode.js - executed lines 209/209; executed functions 9/14
2626
(75%) toolbox/tool-registry-api-client.js - executed lines 152/152; executed functions 21/28
27-
(94%) toolbox/controls/controls.js - executed lines 1686/1686; executed functions 186/197
27+
(94%) toolbox/controls/controls.js - executed lines 1698/1698; executed functions 187/198
2828
(100%) toolbox/controls/controls-api-client.js - executed lines 12/12; executed functions 2/2
2929
(100%) toolbox/objects/objects-api-client.js - executed lines 10/10; executed functions 2/2
3030

tests/playwright/tools/InputMappingV2Tool.spec.mjs

Lines changed: 28 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -256,11 +256,20 @@ test("Controls Input Mapping launch panels, defaults, diagnostics, and workspace
256256
await expect(page.locator("[data-input-mapping-accordion] summary")).toHaveText("Input Mapping");
257257
await expect(page.locator("[data-controller-profile-accordion] summary")).toHaveText("Controller Profile");
258258
await expect(page.locator(".tool-center-panel [data-controller-profile-planning]")).toBeVisible();
259+
const controllerDeviceSelection = page.locator("[data-controller-device-selection]");
260+
await expect(controllerDeviceSelection.locator("[data-input-refresh-devices]")).toBeVisible();
261+
expect(await controllerDeviceSelection.evaluate((node) =>
262+
Array.from(node.children).slice(0, 2).map((child) =>
263+
child.matches("[data-input-refresh-devices]") ? "Refresh Devices" : child.textContent.trim().split(/\s+/)[0],
264+
),
265+
)).toEqual(["Refresh Devices", "Device"]);
259266
await expect(page.getByRole("heading", { name: "Mappings" })).toBeVisible();
260267
await expect(page.locator("[data-input-state-explanation]")).toHaveText("State: Active means the mapping is available to the game. Disabled means the mapping is saved but ignored by the game until re-enabled.");
261268
await expect(page.getByText("Mapping JSON", { exact: true })).toHaveCount(0);
262269
await expect(page.locator("[data-input-mapping-json]")).toHaveCount(0);
263270
await expect(page.getByText("Devices", { exact: true })).toBeVisible();
271+
await expect(page.locator("[data-input-device-guidance]")).toHaveText("Press a button on the controller, then refresh Device Type.");
272+
await expect(page.locator("aside").last().locator("[data-input-refresh-devices]")).toHaveCount(0);
264273
await expect(page.getByText("Status", { exact: true })).toBeVisible();
265274
await expect(page.locator("[data-input-return-workspace]")).toBeVisible();
266275
await expect(page.locator("[data-controller-profile-table] th")).toHaveText([
@@ -706,7 +715,23 @@ test("Controls generates controller profiles, shows fallback status, and mapping
706715
});
707716
const activeProfileInput = page.locator("[data-controller-profile-input-pair][data-controller-profile-input-active='true']");
708717
await expect(activeProfileInput.locator("strong")).toHaveText("Button0");
709-
await expect(activeProfileInput.locator("[data-controller-profile-input-assigned-action]")).toHaveText("Selected Action: Fire");
718+
const activeActionText = activeProfileInput.locator("[data-controller-profile-input-assigned-action]");
719+
await expect(activeActionText).toHaveText("Selected Action: Fire");
720+
await expect(activeActionText).toHaveClass(/text-gold/);
721+
await expect(activeActionText).toHaveCSS("color", "rgb(255, 200, 87)");
722+
await expect(activeProfileInput).not.toHaveClass(/feedback/);
723+
expect(await activeProfileInput.evaluate((node) => {
724+
const style = getComputedStyle(node);
725+
return {
726+
backgroundColor: style.backgroundColor,
727+
borderTopStyle: style.borderTopStyle,
728+
borderTopWidth: style.borderTopWidth,
729+
};
730+
})).toEqual({
731+
backgroundColor: "rgba(0, 0, 0, 0)",
732+
borderTopStyle: "none",
733+
borderTopWidth: "0px",
734+
});
710735
await expect(editingActionsRow.locator("[data-controller-profile-input-pair]").nth(1)).not.toHaveAttribute("data-controller-profile-input-active", "true");
711736
await expect(editingActionsRow.locator("[data-controller-profile-input-pair]").nth(1).locator("[data-controller-profile-input-assigned-action]")).toHaveText("Assigned Action: Move Right");
712737

@@ -732,6 +757,8 @@ test("Controls generates controller profiles, shows fallback status, and mapping
732757
profiles = await controllerProfileRecords(page);
733758
expect(profiles).toHaveLength(1);
734759
expect(profiles[0].mappingProfile).toBe("Arcade Test Pad Profile");
760+
await expect(page.locator("[data-controller-profile-editing-row]")).toContainText("Arcade Test Pad Profile");
761+
await expect(page.locator("[data-controller-profile-editing-actions-row] [data-controller-profile-input-action]")).toHaveCount(18);
735762

736763
expect(profiles).toHaveLength(1);
737764

toolbox/controls/controls.js

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -857,8 +857,9 @@ function updateProfileInputAssignedAction(select) {
857857

858858
function clearControllerProfileInputHighlight() {
859859
elements.controllerProfileList?.querySelectorAll("[data-controller-profile-input-pair]").forEach((pair) => {
860-
pair.classList.remove("feedback");
861860
delete pair.dataset.controllerProfileInputActive;
861+
const status = pair.querySelector("[data-controller-profile-input-assigned-action]");
862+
status?.classList.remove("text-gold");
862863
updateProfileInputAssignedAction(pair.querySelector("[data-controller-profile-input-action]"));
863864
});
864865
}
@@ -874,11 +875,12 @@ function highlightControllerProfileInput(inputName) {
874875
if (!pair) {
875876
return;
876877
}
877-
pair.classList.add("feedback");
878878
pair.dataset.controllerProfileInputActive = "true";
879879
const select = pair.querySelector("[data-controller-profile-input-action]");
880880
updateProfileInputAssignedAction(select);
881-
setText(elements.controllerProfileStatus, `${inputName} selected. ${pair.querySelector("[data-controller-profile-input-assigned-action]")?.textContent || "Assigned Action: Action Required"}.`);
881+
const status = pair.querySelector("[data-controller-profile-input-assigned-action]");
882+
status?.classList.add("text-gold");
883+
setText(elements.controllerProfileStatus, `${inputName} selected. ${status?.textContent || "Assigned Action: Action Required"}.`);
882884
}
883885

884886
function updateControllerProfileInputHighlight() {
@@ -1600,6 +1602,16 @@ function addProfileForDevice(device, source = "detected") {
16001602
renderControllerProfiles();
16011603
return;
16021604
}
1605+
const savedProfile = controllerProfiles.find((candidate) => candidate.id === profile.id) || profile;
1606+
if (source === "default-gamepad") {
1607+
profileEditingRow = {
1608+
id: savedProfile.id,
1609+
values: savedProfile,
1610+
};
1611+
renderAll(`${savedProfile.mappingProfile} saved. Assign Actions for generated profile inputs.`);
1612+
setText(elements.controllerProfileStatus, `Editing ${savedProfile.mappingProfile} controller profile.`);
1613+
return;
1614+
}
16031615
profileEditingRow = null;
16041616
renderAll(`${profile.mappingProfile} saved. Action Required for generated profile inputs.`);
16051617
}

toolbox/controls/index.html

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -127,7 +127,8 @@ <h3>Mappings</h3>
127127
<h3>Controller Profiles</h3>
128128
</div>
129129
<p>Plan how gamepad identities will match saved mapping profiles.</p>
130-
<div class="content-cluster" aria-label="Controller device selection">
130+
<div class="content-cluster" aria-label="Controller device selection" data-controller-device-selection>
131+
<button class="btn" type="button" data-input-refresh-devices>Refresh Devices</button>
131132
<label>
132133
Device Type
133134
<select data-controller-device-select></select>
@@ -174,9 +175,7 @@ <h2>Inspector</h2>
174175
<details class="vertical-accordion" open>
175176
<summary>Devices</summary>
176177
<div class="accordion-body content-stack">
177-
<div class="content-cluster" aria-label="Device diagnostics controls">
178-
<button class="btn" type="button" data-input-refresh-devices>Refresh Devices</button>
179-
</div>
178+
<p class="status" data-input-device-guidance>Press a button on the controller, then refresh Device Type.</p>
180179
<ul data-input-source-diagnostics></ul>
181180
</div>
182181
</details>

0 commit comments

Comments
 (0)