Skip to content

Commit f424497

Browse files
committed
Refine Controls controller profile edit mode and input highlighting - PR_26161_029-controls-controller-profile-edit-mode
1 parent 2589276 commit f424497

7 files changed

Lines changed: 785 additions & 522 deletions

File tree

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,7 @@
1-
docs_build/dev/reports/controls-compact-controller-profile-report.md
2-
docs_build/dev/reports/codex_review.diff
31
docs_build/dev/reports/codex_changed_files.txt
4-
docs_build/dev/reports/playwright_v8_coverage_report.txt
2+
docs_build/dev/reports/codex_review.diff
3+
docs_build/dev/reports/controls-controller-profile-edit-mode-report.md
54
docs_build/dev/reports/coverage_changed_js_guardrail.txt
5+
docs_build/dev/reports/playwright_v8_coverage_report.txt
66
tests/playwright/tools/InputMappingV2Tool.spec.mjs
77
toolbox/controls/controls.js
8-
toolbox/controls/index.html

docs_build/dev/reports/codex_review.diff

Lines changed: 526 additions & 400 deletions
Large diffs are not rendered by default.
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
# PR_26161_029 Controls Controller Profile Edit Mode Report
2+
3+
## Scope
4+
- Updated Controls controller profile rows so saved profiles render as compact summaries outside edit mode.
5+
- Moved generated controller input Action dropdowns into profile edit mode only.
6+
- Added edit-mode gamepad input highlighting for matching generated controller inputs.
7+
- Kept Controls status as Wireframe and kept persistence through the shared DB/mock adapter.
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: `git diff --check`
22+
- PASS: `npx playwright test tests/playwright/tools/InputMappingV2Tool.spec.mjs`
23+
24+
## Manual Validation Steps
25+
- Open Controls and refresh devices with a detected gamepad.
26+
- Add a controller profile and confirm the saved profile row shows only the compact summary.
27+
- Click Edit and confirm profile row values are text while generated input Action dropdowns appear underneath.
28+
- Press a controller button during edit and confirm the matching generated input row highlights with the selected Action.
29+
- Assign generated input Actions, Save, reload, and confirm assignments persist.
30+
- Edit a profile, change an Action, Cancel, reload, and confirm the unsaved change did not persist.
31+
32+
## Skipped Lanes
33+
- Full samples validation skipped by request because this PR only changes Controls UI behavior and targeted Playwright coverage exercises the impacted lane.
34+
35+
## Runtime Engine Behavior
36+
- Confirmed: no runtime engine behavior changed.
37+
38+
## Completion Check
39+
- PASS: Controller Profile Edit shows profile row values as text, not dropdowns.
40+
- PASS: Generated input Action dropdowns appear only in edit mode.
41+
- PASS: Generated input Action dropdowns are hidden outside edit mode.
42+
- PASS: Controller input press during edit highlights the matching generated input.
43+
- PASS: Selected/assigned Action is visibly shown for the pressed input.
44+
- PASS: Editing one input does not alter other inputs.
45+
- PASS: Save persists generated input action assignments after reload.
46+
- PASS: Cancel does not persist unsaved generated input action changes.

docs_build/dev/reports/coverage_changed_js_guardrail.txt

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -6,10 +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-
(0%) src/dev-runtime/persistence/mock-db-store.js - WARNING: changed runtime JS file was not collected by Playwright V8 coverage; advisory only
10-
(0%) src/dev-runtime/persistence/tool-repositories/input-mapping-mock-repository.js - WARNING: changed runtime JS file was not collected by Playwright V8 coverage; advisory only
11-
(91%) toolbox/controls/controls.js - executed lines 1626/1626; executed functions 165/181
9+
(94%) toolbox/controls/controls.js - executed lines 1686/1686; executed functions 186/197
1210

1311
Guardrail warnings:
14-
(0%) src/dev-runtime/persistence/mock-db-store.js - WARNING: changed runtime JS file missing from coverage; advisory only
15-
(0%) src/dev-runtime/persistence/tool-repositories/input-mapping-mock-repository.js - WARNING: changed runtime JS file missing from coverage; advisory only
12+
(100%) none - no changed runtime JS coverage warnings

docs_build/dev/reports/playwright_v8_coverage_report.txt

Lines changed: 5 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -12,30 +12,25 @@ Note: entry percentages use function coverage when available, otherwise line cov
1212
Note: coverage entries are aggregated across every page/tool where coverageReporter.start(page) and coverageReporter.stop(page) ran.
1313

1414
Exercised tool entry points detected:
15-
(89%) Toolbox Index - exercised 4 runtime JS files
15+
(92%) Toolbox Index - exercised 4 runtime JS files
1616
(0%) Tool Template V2 - not exercised by this Playwright run
1717
(59%) Theme V2 Shared JS - exercised 2 runtime JS files
1818

1919
Changed runtime JS files covered:
20-
(0%) src/dev-runtime/persistence/mock-db-store.js - WARNING: changed runtime JS file was not collected by Playwright V8 coverage; advisory only
21-
(0%) src/dev-runtime/persistence/tool-repositories/input-mapping-mock-repository.js - WARNING: changed runtime JS file was not collected by Playwright V8 coverage; advisory only
22-
(91%) toolbox/controls/controls.js - executed lines 1626/1626; executed functions 165/181
20+
(94%) toolbox/controls/controls.js - executed lines 1686/1686; executed functions 186/197
2321

2422
Files with executed line/function counts where available:
2523
(53%) src/engine/api/server-api-client.js - executed lines 159/159; executed functions 10/19
2624
(58%) assets/theme-v2/js/gamefoundry-partials.js - executed lines 603/603; executed functions 30/52
2725
(64%) assets/theme-v2/js/tool-display-mode.js - executed lines 209/209; executed functions 9/14
2826
(75%) toolbox/tool-registry-api-client.js - executed lines 152/152; executed functions 21/28
29-
(91%) toolbox/controls/controls.js - executed lines 1626/1626; executed functions 165/181
27+
(94%) toolbox/controls/controls.js - executed lines 1686/1686; executed functions 186/197
3028
(100%) toolbox/controls/controls-api-client.js - executed lines 12/12; executed functions 2/2
3129
(100%) toolbox/objects/objects-api-client.js - executed lines 10/10; executed functions 2/2
3230

3331
Uncovered or low-coverage changed JS files:
34-
(0%) src/dev-runtime/persistence/mock-db-store.js - WARNING: uncovered changed runtime JS file; advisory only
35-
(0%) src/dev-runtime/persistence/tool-repositories/input-mapping-mock-repository.js - WARNING: uncovered changed runtime JS file; advisory only
32+
(100%) none - no low-coverage changed runtime JS files
3633

3734
Changed JS files considered:
38-
(0%) src/dev-runtime/persistence/mock-db-store.js - changed JS file not collected as browser runtime coverage
39-
(0%) src/dev-runtime/persistence/tool-repositories/input-mapping-mock-repository.js - changed JS file not collected as browser runtime coverage
4035
(0%) tests/playwright/tools/InputMappingV2Tool.spec.mjs - changed JS file not collected as browser runtime coverage
41-
(91%) toolbox/controls/controls.js - changed JS file with browser V8 coverage
36+
(94%) toolbox/controls/controls.js - changed JS file with browser V8 coverage

tests/playwright/tools/InputMappingV2Tool.spec.mjs

Lines changed: 44 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -600,11 +600,13 @@ test("Controls generates controller profiles, shows fallback status, and mapping
600600
expect(await controllerProfileRecords(page)).toHaveLength(0);
601601

602602
await page.evaluate(() => {
603+
window.__arcadeButtons = Array.from({ length: 16 }, () => ({ pressed: false, value: 0 }));
604+
window.__arcadeAxes = [0, 0];
603605
Object.defineProperty(navigator, "getGamepads", {
604606
configurable: true,
605607
value: () => [{
606-
axes: [0, 0],
607-
buttons: Array.from({ length: 16 }, () => ({ pressed: false, value: 0 })),
608+
axes: window.__arcadeAxes,
609+
buttons: window.__arcadeButtons,
608610
id: "Arcade Test Pad",
609611
index: 0,
610612
}],
@@ -628,7 +630,7 @@ test("Controls generates controller profiles, shows fallback status, and mapping
628630
await page.locator("[data-controller-profile-add]").click();
629631
await expect(page.locator("[data-controller-profile-list]")).toContainText("Arcade Test Pad");
630632
await expect(page.locator("[data-controller-profile-list]")).toContainText("Arcade Test Pad Profile");
631-
await expect(page.locator("[data-controller-profile-list]")).toContainText("Action Required");
633+
await expect(page.locator("[data-controller-profile-list]")).toContainText("0/18 Actions assigned");
632634
await expect(page.locator("[data-controller-profile-table] th")).toHaveText([
633635
"Device Type",
634636
"Controller Name",
@@ -637,10 +639,8 @@ test("Controls generates controller profiles, shows fallback status, and mapping
637639
"Action",
638640
]);
639641
await expect(page.locator("[data-controller-profile-row]").first()).not.toContainText("Button0");
640-
await expect(page.locator("[data-controller-profile-actions-row]").first().locator(".content-grid--three")).toBeVisible();
641-
await expect(page.locator("[data-controller-profile-actions-row]").first().locator("[data-controller-profile-input-pair]")).toHaveCount(18);
642-
await expect(page.locator("[data-controller-profile-actions-row]").first().locator("[data-controller-profile-input-pair]").first().locator("strong")).toHaveText("Button0");
643-
await expect(page.locator("[data-controller-profile-actions-row]").first().locator("[data-controller-profile-input-pair]").first().locator("select")).toBeVisible();
642+
await expect(page.locator("[data-controller-profile-actions-row]")).toHaveCount(0);
643+
await expect(page.locator("[data-controller-profile-input-action]")).toHaveCount(0);
644644
await expect(page.locator("[data-controller-profile-fallback-status]")).toContainText("Exact saved profile");
645645

646646
let profiles = await controllerProfileRecords(page);
@@ -673,22 +673,56 @@ test("Controls generates controller profiles, shows fallback status, and mapping
673673
"Axis1",
674674
]);
675675

676-
await page.locator("[data-controller-profile-save-actions]").click();
676+
await page.locator("[data-controller-profile-edit]").click();
677+
const editRow = page.locator("[data-controller-profile-editing-row]");
678+
await expect(editRow.locator("td").nth(0)).toHaveText("Gamepad");
679+
await expect(editRow.locator("td").nth(1)).toHaveText("Arcade Test Pad");
680+
await expect(editRow.locator("td").nth(2)).toHaveText("Arcade Test Pad");
681+
await expect(editRow.locator("td").nth(3)).toHaveText("Arcade Test Pad Profile");
682+
await expect(editRow.locator("select")).toHaveCount(0);
683+
await expect(editRow.locator("input")).toHaveCount(0);
684+
await expect(editRow.locator("button")).toHaveText(["Save", "Cancel"]);
685+
686+
const editingActionsRow = page.locator("[data-controller-profile-editing-actions-row]");
687+
await expect(editingActionsRow.locator(".content-grid--three")).toBeVisible();
688+
await expect(editingActionsRow.locator("[data-controller-profile-input-pair]")).toHaveCount(18);
689+
await expect(editingActionsRow.locator("[data-controller-profile-input-pair]").first().locator("strong")).toHaveText("Button0");
690+
await expect(editingActionsRow.locator("[data-controller-profile-input-action]")).toHaveCount(18);
691+
692+
await page.locator("[data-controller-profile-save]").click();
677693
await expect(page.locator("[data-controller-profile-status]")).toContainText("Action Required");
678694
profiles = await controllerProfileRecords(page);
679695
expect(profiles[0].actions).toEqual([]);
680696

681-
const inputActionSelects = page.locator("[data-controller-profile-input-action]");
697+
const inputActionSelects = editingActionsRow.locator("[data-controller-profile-input-action]");
682698
const inputActionCount = await inputActionSelects.count();
683699
expect(inputActionCount).toBe(profiles[0].inputs.length);
684700
for (let index = 0; index < inputActionCount; index += 1) {
685701
await inputActionSelects.nth(index).selectOption(index === 0 ? "fire" : "moveRight");
686702
}
687-
await page.locator("[data-controller-profile-save-actions]").click();
703+
await expect(inputActionSelects.nth(1)).toHaveValue("moveRight");
704+
await page.evaluate(() => {
705+
window.__arcadeButtons[0] = { pressed: true, value: 1 };
706+
});
707+
const activeProfileInput = page.locator("[data-controller-profile-input-pair][data-controller-profile-input-active='true']");
708+
await expect(activeProfileInput.locator("strong")).toHaveText("Button0");
709+
await expect(activeProfileInput.locator("[data-controller-profile-input-assigned-action]")).toHaveText("Selected Action: Fire");
710+
await expect(editingActionsRow.locator("[data-controller-profile-input-pair]").nth(1)).not.toHaveAttribute("data-controller-profile-input-active", "true");
711+
await expect(editingActionsRow.locator("[data-controller-profile-input-pair]").nth(1).locator("[data-controller-profile-input-assigned-action]")).toHaveText("Assigned Action: Move Right");
712+
713+
await page.locator("[data-controller-profile-save]").click();
688714
profiles = await controllerProfileRecords(page);
689715
expect(profiles[0].actions).toHaveLength(profiles[0].inputs.length);
690716
expect(profiles[0].actions[0]).toBe("fire");
691717
expect(profiles[0].actions[1]).toBe("moveRight");
718+
await expect(page.locator("[data-controller-profile-input-action]")).toHaveCount(0);
719+
720+
await page.locator("[data-controller-profile-edit]").click();
721+
await page.locator("[data-controller-profile-input-action]").first().selectOption("jump");
722+
await page.locator("[data-controller-profile-cancel]").click();
723+
profiles = await controllerProfileRecords(page);
724+
expect(profiles[0].actions[0]).toBe("fire");
725+
await expect(page.locator("[data-controller-profile-input-action]")).toHaveCount(0);
692726

693727
await page.locator("[data-controller-profile-trash]").click();
694728
await expect(page.locator("[data-controller-profile-list]")).toContainText("No controller profiles saved yet.");

0 commit comments

Comments
 (0)