Skip to content

Commit fcd74bb

Browse files
committed
Allow multiple user control profiles per controller without replacement - PR_26163_065-user-controls-multiple-profiles-per-controller
1 parent fa45a1c commit fcd74bb

6 files changed

Lines changed: 282 additions & 313 deletions

File tree

account/user-controls-page.js

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -382,6 +382,7 @@ export class AccountUserControlsPage {
382382
const family = this.profileListFamily(device);
383383
const baseControllerName = normalizeText(device.controllerName) || family;
384384
const baseProfileName = normalizeText(device.mappingProfile) || `${baseControllerName} Profile`;
385+
const profileIds = new Set(this.profiles.map((profile) => normalizeText(profile.id)));
385386
const profileNames = new Set(this.profiles
386387
.filter((profile) => this.profileListFamily(profile) === family)
387388
.map((profile) => normalizeText(profile.mappingProfile).toLowerCase()));
@@ -393,10 +394,18 @@ export class AccountUserControlsPage {
393394
mappingProfile = `${baseControllerName} ${suffix} Profile`;
394395
suffix += 1;
395396
}
397+
const baseProfileId = this.profileIdFor({ controllerId: device.controllerId, mappingProfile });
398+
let profileId = baseProfileId;
399+
let idSuffix = 2;
400+
while (profileIds.has(profileId)) {
401+
profileId = `${baseProfileId}-${idSuffix}`;
402+
idSuffix += 1;
403+
}
396404
return this.normalizeProfile({
397405
controllerId: device.controllerId,
398406
controllerName,
399407
deviceType: device.deviceType,
408+
id: profileId,
400409
inputMappings: normalizeProfileInputMappings(device.inputs),
401410
inputs: device.inputs,
402411
mappingProfile,
@@ -415,7 +424,7 @@ export class AccountUserControlsPage {
415424
const profile = this.uniqueProfileForDevice(device);
416425
let createdProfile = profile;
417426
if (persistImmediately) {
418-
if (!this.saveProfiles([profile, ...this.profiles])) {
427+
if (!this.saveProfiles([...this.profiles, profile])) {
419428
this.setStatus("FAIL: User Controls could not reach the shared DB adapter.");
420429
return;
421430
}
@@ -1311,7 +1320,7 @@ export class AccountUserControlsPage {
13111320
}
13121321
const nextProfiles = this.editingProfile?.id && this.profiles.some((candidate) => candidate.id === this.editingProfile.id)
13131322
? this.profiles.map((candidate) => (candidate.id === this.editingProfile.id ? profile : candidate))
1314-
: [profile, ...this.profiles];
1323+
: [...this.profiles, profile];
13151324
if (!this.saveProfiles(nextProfiles)) {
13161325
this.setStatus("FAIL: User Controls could not reach the shared DB adapter.");
13171326
return;
Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
# PR_26163_065-user-controls-multiple-profiles-per-controller
2+
3+
## Branch Validation
4+
5+
- PASS: Current branch is `main`.
6+
- PASS: Expected branch is `main`.
7+
- Evidence: `git branch --show-current` returned `main`.
8+
9+
## Requirement Checklist
10+
11+
- PASS: Read `docs_build/dev/PROJECT_INSTRUCTIONS.md` before implementation.
12+
- PASS: Every `Create User Control Profile` action for a selected controller creates a brand-new unsaved profile object with a unique generated `id`.
13+
- PASS: Creation no longer reuses, replaces, edits, overwrites, or reopens an existing saved profile for the same controller.
14+
- PASS: Unique profile key/id generation now checks existing profile IDs and suffixes new IDs when the generated base ID is already owned by another saved profile.
15+
- PASS: New profile names still start from generated default names and remain editable before save.
16+
- PASS: Saving a new profile appends it to the current user's profiles instead of replacing an existing record.
17+
- PASS: Existing profiles, including a renamed `1.1 Profile`, remain unchanged when another profile is generated for the same physical controller.
18+
- PASS: A user can create multiple profiles for the same physical controller; Playwright validates two saved profiles with the same `controllerId` and distinct IDs.
19+
- PASS: Preserved the controller dropdown workflow: `[ Refresh Devices ] [ Controller Dropdown ] [ Create User Control Profile ]`.
20+
- PASS: Detection/refresh still creates zero profiles.
21+
- PASS: Did not change `toolbox/controls`; those files remain game-owned Controls and are outside this PR.
22+
23+
## Search And Diff Evidence
24+
25+
- PASS: `git diff --name-only` contains only account User Controls runtime, targeted Playwright coverage, and report artifacts.
26+
- PASS: `git diff --name-only` contains no `toolbox/controls` files.
27+
- PASS: `rg -n "baseProfileId|profileIds|\\.\\.\\.this\\.profiles, profile|1\\.1 Profile|Studio Flight Pad Profile" account/user-controls-page.js tests/playwright/tools/InputMappingV2Tool.spec.mjs` shows unique ID generation, append-on-save, and the Playwright 1.1 regression path.
28+
29+
## Changed Files
30+
31+
- `account/user-controls-page.js`
32+
- `tests/playwright/tools/InputMappingV2Tool.spec.mjs`
33+
- `docs_build/dev/reports/playwright_v8_coverage_report.txt`
34+
- `docs_build/dev/reports/PR_26163_065-user-controls-multiple-profiles-per-controller.md`
35+
- `docs_build/dev/reports/codex_changed_files.txt`
36+
- `docs_build/dev/reports/codex_review.diff`
37+
38+
## Impacted Lane
39+
40+
- Account/User Controls runtime lane.
41+
- Targeted Account/User Controls Playwright lane.
42+
- Required legacy workspace command: `npm run test:workspace-v2`.
43+
44+
Note: `npm run test:workspace-v2` is a legacy command name retained by repo scripts.
45+
46+
## Skipped Lanes
47+
48+
- Full samples smoke: SKIP. Safe because this PR changes only account User Controls profile generation and targeted Playwright coverage; no sample JSON, sample loader, or game runtime sample path changed.
49+
- Engine input lane: SKIP. Safe because `src/engine/input` was consumed but not modified.
50+
- Toolbox Controls lane: SKIP. Safe because no `toolbox/controls` files changed.
51+
52+
## Testing Performed
53+
54+
- PASS: `node --check account/user-controls-page.js`
55+
- PASS: `node --check tests/playwright/tools/InputMappingV2Tool.spec.mjs`
56+
- PASS: `git diff --check -- account/user-controls-page.js tests/playwright/tools/InputMappingV2Tool.spec.mjs`
57+
- PASS: `rg -n "<style| on[a-z]+=" account/user-controls.html` returned no inline style/event handler matches.
58+
- PASS: `npx playwright test tests/playwright/tools/InputMappingV2Tool.spec.mjs --grep "User Controls owns physical input mapping accordions and profiles|selected controller dropdown device" --reporter=line` passed 2 tests.
59+
- PASS: `npm run test:workspace-v2` passed; workspace-contract lane reported 5 passed.
60+
61+
## Playwright Result
62+
63+
- PASS: Targeted Account/User Controls Playwright checks passed.
64+
- PASS: Required `npm run test:workspace-v2` passed.
65+
66+
## V8 Coverage
67+
68+
- PASS: `docs_build/dev/reports/playwright_v8_coverage_report.txt` includes changed runtime JavaScript coverage.
69+
- PASS: `(92%) account/user-controls-page.js - changed runtime JS file with browser V8 coverage`.
70+
71+
## Manual Validation Steps
72+
73+
1. Open `/account/user-controls.html` while signed in.
74+
2. In Game Controllers, click Refresh Devices and select a detected controller from the Controller dropdown.
75+
3. Click Create User Control Profile.
76+
4. Rename the editing profile to `1.1` and save.
77+
5. Confirm `1.1 Profile` remains visible as a saved profile.
78+
6. Select the same controller again and click Create User Control Profile.
79+
7. Confirm a distinct new editable unsaved profile opens with a generated default name.
80+
8. Save it and confirm both `1.1 Profile` and the new profile exist with distinct profile IDs.
81+
9. Refresh/detect devices again and confirm no profile is created until Create User Control Profile is clicked.
82+
83+
## Samples Validation Decision
84+
85+
- SKIP: Full samples smoke was not run because no samples, sample JSON, sample loader, or production game runtime behavior changed.
86+
87+
## ZIP Artifact
88+
89+
- PASS: Repo-structured delta ZIP produced at `tmp/PR_26163_065-user-controls-multiple-profiles-per-controller_delta.zip`.
Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
1-
account/user-controls.html
21
account/user-controls-page.js
32
tests/playwright/tools/InputMappingV2Tool.spec.mjs
43
docs_build/dev/reports/playwright_v8_coverage_report.txt
5-
docs_build/dev/reports/PR_26163_064-user-controls-controller-dropdown-selection.md
4+
docs_build/dev/reports/PR_26163_065-user-controls-multiple-profiles-per-controller.md
65
docs_build/dev/reports/codex_review.diff
76
docs_build/dev/reports/codex_changed_files.txt

0 commit comments

Comments
 (0)