diff --git a/assets/theme-v2/css/tables.css b/assets/theme-v2/css/tables.css index 5e0d7cf18..8289fd805 100644 --- a/assets/theme-v2/css/tables.css +++ b/assets/theme-v2/css/tables.css @@ -115,12 +115,8 @@ td { cursor: pointer } -.data-table [data-game-row][data-game-active="true"] { - background: color-mix(in srgb, var(--gold) 14%, var(--panel)) -} - -.data-table [data-game-row][data-game-active="true"] > th, -.data-table [data-game-row][data-game-active="true"] > td { +.data-table [data-game-active-cell="true"] { + box-shadow: inset var(--space-3) 0 0 var(--gold); border-bottom-color: var(--gold-border-muted) } diff --git a/docs_build/dev/reports/PR_26174_ALFA_016-game-hub-row-edit-add-selected-state-branch-validation.txt b/docs_build/dev/reports/PR_26174_ALFA_016-game-hub-row-edit-add-selected-state-branch-validation.txt new file mode 100644 index 000000000..5fcb0a000 --- /dev/null +++ b/docs_build/dev/reports/PR_26174_ALFA_016-game-hub-row-edit-add-selected-state-branch-validation.txt @@ -0,0 +1,9 @@ +Branch Validation: PASS + +PASS - Current branch is pr/26174-ALFA-016-game-hub-row-edit-add-selected-state. +PASS - Branch was created from pr/26174-ALFA-015-game-hub-actions-and-setup-cleanup at ef771ff76. +PASS - Worktree was clean before creating the PR branch. +PASS - Scope is limited to Game Hub table add/edit selected-state behavior, Theme V2 table styling, targeted Playwright coverage, and required reports. +PASS - No protected Project Instructions files were modified. +PASS - No merge to main was performed. + diff --git a/docs_build/dev/reports/PR_26174_ALFA_016-game-hub-row-edit-add-selected-state-manual-validation-notes.txt b/docs_build/dev/reports/PR_26174_ALFA_016-game-hub-row-edit-add-selected-state-manual-validation-notes.txt new file mode 100644 index 000000000..775656dc9 --- /dev/null +++ b/docs_build/dev/reports/PR_26174_ALFA_016-game-hub-row-edit-add-selected-state-manual-validation-notes.txt @@ -0,0 +1,12 @@ +Manual Validation Notes + +PASS - Confirmed active-game selected styling is a thin Game-cell indicator, not a filled row background. +PASS - Confirmed active game uses the same background color as non-active game cells. +PASS - Confirmed active Game and Edit buttons do not use selected button styling. +PASS - Confirmed Edit remains a plain action until it opens an inline edit row. +PASS - Confirmed inline edit row shows Game, Purpose, Status, Owner, Actions columns with Save and Cancel. +PASS - Confirmed Game textbox is visible during edit and read-only because no rename API exists in the current Game Hub contract. +PASS - Confirmed Add Game row appears under the game table and expands to Game, Purpose, Status, Owner, Actions with Save and Cancel. +PASS - Confirmed add and edit saves use the existing repository API/service methods. +PASS - Confirmed Source Idea and Readiness Output child rows remain under expanded game parent rows. +PASS - Confirmed guest users can browse/select games but cannot add or edit. diff --git a/docs_build/dev/reports/PR_26174_ALFA_016-game-hub-row-edit-add-selected-state-requirement-checklist.txt b/docs_build/dev/reports/PR_26174_ALFA_016-game-hub-row-edit-add-selected-state-requirement-checklist.txt new file mode 100644 index 000000000..bf2ab869c --- /dev/null +++ b/docs_build/dev/reports/PR_26174_ALFA_016-game-hub-row-edit-add-selected-state-requirement-checklist.txt @@ -0,0 +1,17 @@ +Requirement Checklist: PASS + +PASS - Selected state now appears as a thin indicator on the Game cell for the active game. +PASS - Active game does not use a filled row background. +PASS - Active game does not use a different background color. +PASS - Active Game button does not use selected button styling. +PASS - Edit button does not look selected while a row is merely active. +PASS - Add Game button/row appears under the game table. +PASS - Add row includes Game textbox, Purpose dropdown, and Status dropdown. +PASS - Add row actions show Save and Cancel. +PASS - Edit row actions show Save and Cancel. +PASS - Columns remain Game, Purpose, Status, Owner, Actions. +PASS - Source Idea child rows are preserved. +PASS - Readiness Output child rows are preserved. +PASS - table_first_ui.md and the Idea Board table-first add-row/edit-row pattern were followed. +PASS - No browser-owned product data was introduced. +PASS - No silent fallbacks were introduced. diff --git a/docs_build/dev/reports/PR_26174_ALFA_016-game-hub-row-edit-add-selected-state-validation-lane.txt b/docs_build/dev/reports/PR_26174_ALFA_016-game-hub-row-edit-add-selected-state-validation-lane.txt new file mode 100644 index 000000000..9b5897683 --- /dev/null +++ b/docs_build/dev/reports/PR_26174_ALFA_016-game-hub-row-edit-add-selected-state-validation-lane.txt @@ -0,0 +1,11 @@ +Validation Lane: PASS + +Commands: +1. npx playwright test tests/playwright/tools/GameHubMockRepository.spec.mjs -g "Game Hub creates, opens, and deletes mock games|Game Hub validates game parent rows and child tables|Game Hub preserves guest browsing and blocks guest saves|Game Hub shows a creator-safe empty state when no projects exist|Game Hub shows a creator-safe unavailable state when project list API fails|Game Hub displays and edits game purpose and member role|Game Hub readiness child rows update from mock game state" +Result: PASS - 7 passed. + +2. npx playwright test tests/playwright/tools/IdeaBoardTableNotes.spec.mjs -g "Idea Board uses accordion table ideas and notes" +Result: PASS - 1 passed. + +3. git diff --check -- assets/theme-v2/css/tables.css toolbox/game-hub/game-hub.js tests/playwright/tools/GameHubMockRepository.spec.mjs +Result: PASS. diff --git a/docs_build/dev/reports/PR_26174_ALFA_016-game-hub-row-edit-add-selected-state.md b/docs_build/dev/reports/PR_26174_ALFA_016-game-hub-row-edit-add-selected-state.md new file mode 100644 index 000000000..8f9f53658 --- /dev/null +++ b/docs_build/dev/reports/PR_26174_ALFA_016-game-hub-row-edit-add-selected-state.md @@ -0,0 +1,21 @@ +# PR_26174_ALFA_016-game-hub-row-edit-add-selected-state + +## Purpose + +Move Game Hub add/edit behavior into the game table and correct selected-state styling. + +## Summary + +- Moved the active-game indicator from the Actions edit button to a thin Game-cell indicator. +- Removed filled active-game background styling and selected-button appearance. +- Kept Edit as a plain row action and rendered Save/Cancel only while a row is editing. +- Added a bottom Add Game row that expands into Game, Purpose, and Status fields with Save/Cancel actions. +- Removed the old sidebar add-game form while preserving the existing API/service contract. +- Preserved Game, Purpose, Status, Owner, and Actions columns. +- Preserved Source Idea and Readiness Output child rows under game parent rows. + +## Validation + +PASS - `npx playwright test tests/playwright/tools/GameHubMockRepository.spec.mjs -g "Game Hub creates, opens, and deletes mock games|Game Hub validates game parent rows and child tables|Game Hub preserves guest browsing and blocks guest saves|Game Hub shows a creator-safe empty state when no projects exist|Game Hub shows a creator-safe unavailable state when project list API fails|Game Hub displays and edits game purpose and member role|Game Hub readiness child rows update from mock game state"` +PASS - `npx playwright test tests/playwright/tools/IdeaBoardTableNotes.spec.mjs -g "Idea Board uses accordion table ideas and notes"` +PASS - `git diff --check -- assets/theme-v2/css/tables.css toolbox/game-hub/game-hub.js tests/playwright/tools/GameHubMockRepository.spec.mjs` diff --git a/docs_build/dev/reports/codex_changed_files.txt b/docs_build/dev/reports/codex_changed_files.txt index 416904cbe..5e81caa5c 100644 --- a/docs_build/dev/reports/codex_changed_files.txt +++ b/docs_build/dev/reports/codex_changed_files.txt @@ -1,5 +1,3 @@ assets/theme-v2/css/tables.css tests/playwright/tools/GameHubMockRepository.spec.mjs -tests/playwright/tools/IdeaBoardTableNotes.spec.mjs toolbox/game-hub/game-hub.js -toolbox/game-hub/index.html diff --git a/docs_build/dev/reports/codex_review.diff b/docs_build/dev/reports/codex_review.diff index 31be248da..f6a9821e0 100644 --- a/docs_build/dev/reports/codex_review.diff +++ b/docs_build/dev/reports/codex_review.diff @@ -1,301 +1,116 @@ diff --git a/assets/theme-v2/css/tables.css b/assets/theme-v2/css/tables.css -index c39ef19f0..5e0d7cf18 100644 +index b4c74d66c..8289fd805 100644 --- a/assets/theme-v2/css/tables.css +++ b/assets/theme-v2/css/tables.css -@@ -115,6 +115,15 @@ td { - cursor: pointer +@@ -116,10 +116,7 @@ td { + } + + .data-table [data-game-active-cell="true"] { +- background: color-mix(in srgb, var(--gold) 14%, var(--panel)) +-} +- +-.data-table [data-game-active-cell="true"] { ++ box-shadow: inset var(--space-3) 0 0 var(--gold); + border-bottom-color: var(--gold-border-muted) } -+.data-table [data-game-row][data-game-active="true"] { -+ background: color-mix(in srgb, var(--gold) 14%, var(--panel)) -+} -+ -+.data-table [data-game-row][data-game-active="true"] > th, -+.data-table [data-game-row][data-game-active="true"] > td { -+ border-bottom-color: var(--gold-border-muted) -+} -+ - .idea-board-idea-label { - display: inline-flex; - align-items: center; diff --git a/tests/playwright/tools/GameHubMockRepository.spec.mjs b/tests/playwright/tools/GameHubMockRepository.spec.mjs -index c4bceb838..cf21ba090 100644 +index 88a06e1cc..2363ff88d 100644 --- a/tests/playwright/tools/GameHubMockRepository.spec.mjs +++ b/tests/playwright/tools/GameHubMockRepository.spec.mjs -@@ -249,10 +249,12 @@ test("Game Hub creates, opens, and deletes mock games", async ({ page }) => { - try { - await expect(page.locator(".tool-workspace")).toBeVisible(); - await expect(page.locator("style, [style], script:not([src])")).toHaveCount(0); -- await expect(page.getByRole("button", { name: "Create Game" })).toHaveClass("btn"); -- await expect(page.getByRole("button", { name: "Create Game" })).toBeEnabled(); -+ await expect(page.getByRole("button", { name: "Add" })).toHaveClass("btn"); -+ await expect(page.getByRole("button", { name: "Add" })).toBeEnabled(); - await expect(page.getByRole("button", { name: "Delete Open Game" })).toHaveClass("btn"); - await expect(page.getByRole("button", { name: "Delete Open Game" })).toBeEnabled(); -+ await expect(page.locator("summary").filter({ hasText: /^Game Setup$/ })).toHaveCount(0); -+ await expect(page.getByRole("link", { name: "Open Game Journey" })).toHaveCount(0); - await expect(page.locator("[data-project-record-status]")).toHaveText("Game table loaded."); - await expect(page.locator("[data-game-project-information]")).toHaveCount(0); - await expect(page.locator("[data-project-records-table]")).toHaveCount(0); -@@ -281,11 +283,17 @@ test("Game Hub creates, opens, and deletes mock games", async ({ page }) => { - ]); - await expect(page.locator("[data-game-rows-table='true'] thead")).not.toContainText(/Role|Next Tool/); - const demoGameRow = page.locator("[data-game-row='demo-game']"); -- await expect(demoGameRow.locator("td")).toHaveText(["Game", "Under Construction", "User 1", "Open Demo Game (Active)"]); -+ await expect(demoGameRow.locator("td")).toHaveText(["Game", "Under Construction", "User 1", "Edit"]); -+ await expect(demoGameRow).toHaveAttribute("data-game-active", "true"); -+ await expect(demoGameRow).toHaveAttribute("aria-current", "true"); -+ const activeRowBackground = await demoGameRow.evaluate((row) => getComputedStyle(row).backgroundColor); -+ expect(activeRowBackground).not.toBe("rgba(0, 0, 0, 0)"); -+ expect(activeRowBackground).not.toBe("transparent"); +@@ -290,12 +290,19 @@ test("Game Hub creates, opens, and deletes mock games", async ({ page }) => { + await expect(demoGameRow).toHaveAttribute("data-game-active", "true"); + await expect(demoGameRow).toHaveAttribute("aria-current", "true"); + await expect(demoGameRow.locator("th[data-game-active-cell='true']")).toContainText("Demo Game"); +- const activeCellBackground = await demoGameRow.locator("th[data-game-active-cell='true']").evaluate((cell) => getComputedStyle(cell).backgroundColor); +- expect(activeCellBackground).not.toBe("rgba(0, 0, 0, 0)"); +- expect(activeCellBackground).not.toBe("transparent"); ++ const activeCellStyle = await demoGameRow.locator("th[data-game-active-cell='true']").evaluate((cell) => { ++ const styles = getComputedStyle(cell); ++ return { ++ backgroundColor: styles.backgroundColor, ++ boxShadow: styles.boxShadow, ++ }; ++ }); ++ const inactiveCellBackground = await page.locator("[data-game-row='gravity-demo'] th").evaluate((cell) => getComputedStyle(cell).backgroundColor); ++ expect(activeCellStyle.backgroundColor).toBe(inactiveCellBackground); ++ expect(activeCellStyle.boxShadow).not.toBe("none"); await expect(demoGameRow.locator("> .status")).toHaveCount(0); await expect(demoGameRow.locator("[data-game-toggle='demo-game']")).toHaveAttribute("aria-expanded", "false"); -- await expect(demoGameRow.getByRole("button", { name: "Open Demo Game (Active)" })).toHaveClass(/primary/); -- await expect(demoGameRow.getByRole("button", { name: "Open Demo Game (Active)" })).toHaveAttribute("aria-current", "true"); -+ await expect(demoGameRow.getByRole("button", { name: "Edit Demo Game" })).toHaveText("Edit"); -+ await expect(demoGameRow.getByRole("button", { name: "Edit Demo Game" })).toHaveClass(/primary/); -+ await expect(demoGameRow.getByRole("button", { name: "Edit Demo Game" })).toHaveAttribute("aria-current", "true"); - await demoGameRow.locator("[data-game-toggle='demo-game']").click(); - await expect(demoGameRow.locator("[data-game-toggle='demo-game']")).toHaveAttribute("aria-expanded", "true"); - const demoChildRows = page.locator("[data-game-expanded-row='demo-game']"); -@@ -313,18 +321,21 @@ test("Game Hub creates, opens, and deletes mock games", async ({ page }) => { - await expect(page.locator("[data-game-expanded-row='demo-game']")).toHaveCount(0); - - await page.getByLabel("Game Name").fill("Launch Test Game"); -- await page.getByRole("button", { name: "Create Game" }).click(); -+ await page.getByRole("button", { name: "Add" }).click(); +- await expect(demoGameRow.locator("[data-game-toggle='demo-game']")).toHaveClass(/primary/); ++ await expect(demoGameRow.locator("[data-game-toggle='demo-game']")).not.toHaveClass(/primary/); + await expect(demoGameRow.locator("[data-game-toggle='demo-game']")).toHaveAttribute("aria-current", "true"); + await expect(demoGameRow.getByRole("button", { name: "Edit Demo Game" })).toHaveText("Edit"); + await expect(demoGameRow.getByRole("button", { name: "Edit Demo Game" })).not.toHaveClass(/primary/); +@@ -335,7 +342,7 @@ test("Game Hub creates, opens, and deletes mock games", async ({ page }) => { + await addGameRow.getByRole("button", { name: "Save" }).click(); await expect(page.locator("[data-game-list]")).toContainText("Launch Test Game"); -- await expect(page.locator("[data-game-row='launch-test-game-1']").getByRole("button", { name: "Open Launch Test Game (Active)" })).toHaveClass(/primary/); -+ await expect(page.locator("[data-game-row='launch-test-game-1']")).toHaveAttribute("data-game-active", "true"); -+ await expect(page.locator("[data-game-row='launch-test-game-1']").getByRole("button", { name: "Edit Launch Test Game" })).toHaveClass(/primary/); - await expect(page.locator("[data-game-hub-log]")).toHaveText("Created and opened Launch Test Game."); - - await page.getByLabel("Game Name").fill("Archive Game"); -- await page.getByRole("button", { name: "Create Game" }).click(); -- await expect(page.locator("[data-game-row='archive-game-2']").getByRole("button", { name: "Open Archive Game (Active)" })).toHaveClass(/primary/); -+ await page.getByRole("button", { name: "Add" }).click(); -+ await expect(page.locator("[data-game-row='archive-game-2']")).toHaveAttribute("data-game-active", "true"); -+ await expect(page.locator("[data-game-row='archive-game-2']").getByRole("button", { name: "Edit Archive Game" })).toHaveClass(/primary/); - -- await page.getByRole("button", { name: "Open Launch Test Game" }).click(); -- await expect(page.locator("[data-game-row='launch-test-game-1']").getByRole("button", { name: "Open Launch Test Game (Active)" })).toHaveAttribute("data-game-active", "true"); -- await expect(page.locator("[data-game-hub-log]")).toHaveText("Opened Launch Test Game."); -+ await page.getByRole("button", { name: "Edit Launch Test Game" }).click(); -+ await expect(page.locator("[data-game-row='launch-test-game-1']")).toHaveAttribute("data-game-active", "true"); -+ await expect(page.locator("[data-game-row='launch-test-game-1']").getByRole("button", { name: "Edit Launch Test Game" })).toHaveAttribute("data-game-active", "true"); -+ await expect(page.locator("[data-game-hub-log]")).toHaveText("Editing Launch Test Game."); - - await page.getByRole("button", { name: "Delete Open Game" }).click(); - await expect(page.locator("[data-game-row='launch-test-game-1']")).toHaveCount(0); -@@ -472,19 +483,19 @@ test("Game Hub preserves guest browsing and blocks guest saves", async ({ page } + await expect(page.locator("[data-game-row='launch-test-game-1']")).toHaveAttribute("data-game-active", "true"); +- await expect(page.locator("[data-game-row='launch-test-game-1'] [data-game-toggle='launch-test-game-1']")).toHaveClass(/primary/); ++ await expect(page.locator("[data-game-row='launch-test-game-1'] [data-game-toggle='launch-test-game-1']")).not.toHaveClass(/primary/); + await expect(page.locator("[data-game-row='launch-test-game-1']").getByRole("button", { name: "Edit Launch Test Game" })).not.toHaveClass(/primary/); + await expect(page.locator("[data-game-row='launch-test-game-1'] td").nth(0)).toHaveText("Learning Game"); + await expect(page.locator("[data-game-row='launch-test-game-1'] td").nth(1)).toHaveText("Ready for Testing"); +@@ -362,11 +369,11 @@ test("Game Hub creates, opens, and deletes mock games", async ({ page }) => { + await page.locator("[data-game-add-row='input']").getByLabel("Game").fill("Archive Game"); + await page.locator("[data-game-add-row='input']").getByRole("button", { name: "Save" }).click(); + await expect(page.locator("[data-game-row='archive-game-2']")).toHaveAttribute("data-game-active", "true"); +- await expect(page.locator("[data-game-row='archive-game-2'] [data-game-toggle='archive-game-2']")).toHaveClass(/primary/); ++ await expect(page.locator("[data-game-row='archive-game-2'] [data-game-toggle='archive-game-2']")).not.toHaveClass(/primary/); + + await page.locator("[data-game-row='launch-test-game-1'] [data-game-toggle='launch-test-game-1']").click(); + await expect(page.locator("[data-game-row='launch-test-game-1']")).toHaveAttribute("data-game-active", "true"); +- await expect(page.locator("[data-game-row='launch-test-game-1'] [data-game-toggle='launch-test-game-1']")).toHaveClass(/primary/); ++ await expect(page.locator("[data-game-row='launch-test-game-1'] [data-game-toggle='launch-test-game-1']")).not.toHaveClass(/primary/); + await expect(page.locator("[data-game-row='launch-test-game-1']").getByRole("button", { name: "Edit Launch Test Game" })).not.toHaveClass(/primary/); + await expect(page.locator("[data-game-hub-log]")).toHaveText("Selected Launch Test Game."); + +@@ -516,7 +523,7 @@ test("Game Hub preserves guest browsing and blocks guest saves", async ({ page } const failures = await openRepoPage(page, "/toolbox/game-hub/index.html"); try { -- await expect(page.locator("[data-game-row='demo-game']").getByRole("button", { name: "Open Demo Game (Active)" })).toHaveClass(/primary/); -+ await expect(page.locator("[data-game-row='demo-game']").getByRole("button", { name: "Edit Demo Game" })).toHaveClass(/primary/); +- await expect(page.locator("[data-game-row='demo-game'] [data-game-toggle='demo-game']")).toHaveClass(/primary/); ++ await expect(page.locator("[data-game-row='demo-game'] [data-game-toggle='demo-game']")).not.toHaveClass(/primary/); + await expect(page.locator("[data-game-row='demo-game']").getByRole("button", { name: "Edit Demo Game" })).not.toHaveClass(/primary/); + await expect(page.locator("[data-game-row='demo-game']").getByRole("button", { name: "Edit Demo Game" })).toBeDisabled(); await expect(page.locator("[data-game-list]")).toContainText("Gravity Demo"); - await expect(page.locator("[data-project-record-status]")).toHaveText("Game table loaded. Sign in to save changes."); - await expect(page.locator("[data-project-records-table]")).toHaveCount(0); -- await expect(page.getByRole("button", { name: "Create Game" })).toBeDisabled(); -+ await expect(page.getByRole("button", { name: "Add" })).toBeDisabled(); - await expect(page.getByRole("button", { name: "Delete Open Game" })).toBeDisabled(); - await expect(page.getByLabel("Game Name")).toBeDisabled(); - await expect(page.getByLabel("Game Purpose")).toBeDisabled(); - await expect(page.getByLabel("Game Status")).toBeDisabled(); +@@ -530,7 +537,7 @@ test("Game Hub preserves guest browsing and blocks guest saves", async ({ page } await expect(page.getByLabel("Current User Role")).toBeDisabled(); -- await page.getByRole("button", { name: "Open Gravity Demo" }).click(); -- await expect(page.locator("[data-game-row='gravity-demo']").getByRole("button", { name: "Open Gravity Demo (Active)" })).toHaveClass(/primary/); -+ await page.getByRole("button", { name: "Edit Gravity Demo" }).click(); -+ await expect(page.locator("[data-game-row='gravity-demo']").getByRole("button", { name: "Edit Gravity Demo" })).toHaveClass(/primary/); + await page.locator("[data-game-row='gravity-demo'] [data-game-toggle='gravity-demo']").click(); +- await expect(page.locator("[data-game-row='gravity-demo'] [data-game-toggle='gravity-demo']")).toHaveClass(/primary/); ++ await expect(page.locator("[data-game-row='gravity-demo'] [data-game-toggle='gravity-demo']")).not.toHaveClass(/primary/); + await expect(page.locator("[data-game-row='gravity-demo']").getByRole("button", { name: "Edit Gravity Demo" })).toBeDisabled(); await expect(page.locator("[data-game-hub-log]")).toHaveText("Sign in to create or update Game Hub projects."); - await expectNoPageFailures(failures); -@@ -677,8 +688,8 @@ test("Game Hub displays and edits game purpose and member role", async ({ page } - - await page.getByLabel("Game Purpose").selectOption("Capability Demo"); - await page.getByLabel("Game Name").fill("Purpose Review Game"); -- await page.getByRole("button", { name: "Create Game" }).click(); -- await expect(page.locator("[data-game-row='purpose-review-game-1']").getByRole("button", { name: "Open Purpose Review Game (Active)" })).toHaveClass(/primary/); -+ await page.getByRole("button", { name: "Add" }).click(); -+ await expect(page.locator("[data-game-row='purpose-review-game-1']").getByRole("button", { name: "Edit Purpose Review Game" })).toHaveClass(/primary/); +@@ -738,7 +745,7 @@ test("Game Hub displays and edits game purpose and member role", async ({ page } + await addRow.getByLabel("Game").fill("Purpose Review Game"); + await addRow.getByLabel("Purpose").selectOption("Capability Demo"); + await addRow.getByRole("button", { name: "Save" }).click(); +- await expect(page.locator("[data-game-row='purpose-review-game-1'] [data-game-toggle='purpose-review-game-1']")).toHaveClass(/primary/); ++ await expect(page.locator("[data-game-row='purpose-review-game-1'] [data-game-toggle='purpose-review-game-1']")).not.toHaveClass(/primary/); + await expect(page.locator("[data-game-row='purpose-review-game-1']").getByRole("button", { name: "Edit Purpose Review Game" })).not.toHaveClass(/primary/); await expect(page.locator("[data-game-row='purpose-review-game-1'] td").nth(0)).toHaveText("Capability Demo"); await expect(page.getByLabel("Current User Role")).toHaveValue("Owner"); - await expect(page.locator("[data-game-list]")).toContainText("Purpose Review Game"); -@@ -714,7 +725,7 @@ test("Game Hub readiness child rows update from mock game state", async ({ page - ]); - - await page.getByLabel("Game Name").fill("Progress Review Game"); -- await page.getByRole("button", { name: "Create Game" }).click(); -+ await page.getByRole("button", { name: "Add" }).click(); - await expect(page.locator("[data-game-project-information]")).toHaveCount(0); - await expect(page.locator("[data-game-list]")).toContainText("Progress Review Game"); - const progressReviewRow = page.locator("[data-game-row='progress-review-game-1']"); -@@ -723,7 +734,7 @@ test("Game Hub readiness child rows update from mock game state", async ({ page +@@ -785,7 +792,7 @@ test("Game Hub readiness child rows update from mock game state", async ({ page await expect(readinessOutputTable).toContainText("Progress Review Game identity ready"); await page.getByRole("button", { name: "Delete Open Game" }).click(); -- await expect(page.locator("[data-game-row='demo-game']").getByRole("button", { name: "Open Demo Game (Active)" })).toHaveClass(/primary/); -+ await expect(page.locator("[data-game-row='demo-game']").getByRole("button", { name: "Edit Demo Game" })).toHaveClass(/primary/); +- await expect(page.locator("[data-game-row='demo-game'] [data-game-toggle='demo-game']")).toHaveClass(/primary/); ++ await expect(page.locator("[data-game-row='demo-game'] [data-game-toggle='demo-game']")).not.toHaveClass(/primary/); + await expect(page.locator("[data-game-row='demo-game']").getByRole("button", { name: "Edit Demo Game" })).not.toHaveClass(/primary/); await demoGameRow.locator("[data-game-toggle='demo-game']").click(); readinessOutputTable = page.locator("[data-game-expanded-row='demo-game'][data-game-child-row='readiness-output'] [data-game-child-table='readiness-output']"); - await expect(readinessOutputTable).toContainText("Demo Game identity ready"); -diff --git a/tests/playwright/tools/IdeaBoardTableNotes.spec.mjs b/tests/playwright/tools/IdeaBoardTableNotes.spec.mjs -index c7bfbe90c..b1faf33d8 100644 ---- a/tests/playwright/tools/IdeaBoardTableNotes.spec.mjs -+++ b/tests/playwright/tools/IdeaBoardTableNotes.spec.mjs -@@ -427,7 +427,9 @@ test("Idea Board uses accordion table ideas and notes", async ({ page }) => { - ]); - await expect(page.getByRole("button", { name: "Delete Open Game" })).toHaveCount(0); - await expect(page.locator("main")).not.toContainText(/\bproject records\b|\bAPI\b|\bDB\b|\bmock\b|\bseed\b|\bdebug\b|\binternal\b/i); -- await page.getByRole("link", { name: "Open Game Journey" }).click(); -+ await expect(page.getByRole("link", { name: "Open Game Journey" })).toHaveCount(0); -+ const createdGameKey = new URL(page.url()).searchParams.get("game"); -+ await page.goto(`${server.baseUrl}/toolbox/game-journey/index.html?game=${createdGameKey}`, { waitUntil: "networkidle" }); - await page.waitForURL(/\/toolbox\/game-journey\/index\.html\?game=lantern-reef-\d+$/); - await expect(page.locator("[data-journey-active-game]")).toHaveText("Active game: Lantern Reef."); - const journeyNoteNames = await page.locator("[data-journey-summary-body] [data-journey-note-button]").evaluateAll((buttons) => ( diff --git a/toolbox/game-hub/game-hub.js b/toolbox/game-hub/game-hub.js -index ad2eee2f4..661f342c0 100644 +index 096b588bc..888c75524 100644 --- a/toolbox/game-hub/game-hub.js +++ b/toolbox/game-hub/game-hub.js -@@ -16,7 +16,6 @@ const elements = { - nameInput: document.querySelector("[data-game-name-input]"), - progressChecklist: document.querySelector("[data-game-progress-checklist]"), - gameList: document.querySelector("[data-game-list]"), -- gameJourneyLink: document.querySelector("[data-game-journey-link]"), - projectRecordStatus: document.querySelector("[data-project-record-status]"), - purposeInput: document.querySelector("[data-game-purpose-input]"), - gameStatusInput: document.querySelector("[data-game-status-input]"), -@@ -198,11 +197,12 @@ function createGameButton(game, isActive) { - button.className = isActive ? "btn primary" : "btn"; - button.type = "button"; - button.dataset.gameOpen = game.id; -+ button.setAttribute("aria-label", `Edit ${game.name}`); - if (isActive) { - button.dataset.gameActive = "true"; - button.setAttribute("aria-current", "true"); - } -- button.textContent = isActive ? `Open ${game.name} (Active)` : `Open ${game.name}`; -+ button.textContent = "Edit"; - return button; - } +@@ -256,7 +256,7 @@ function createInput(value, datasetName, ariaLabel, options = {}) { -@@ -357,6 +357,7 @@ function renderGameParentRow(tbody, game, activeGame, progress) { - row.dataset.gameRow = game.id; + function createGameToggleButton(game, expanded, active) { + const button = document.createElement("button"); +- button.className = active ? "btn btn--compact primary" : "btn btn--compact"; ++ button.className = "btn btn--compact"; + button.type = "button"; + button.dataset.gameToggle = game.id; if (active) { - row.dataset.gameActive = "true"; -+ row.setAttribute("aria-current", "true"); - } - - const nameCell = document.createElement("th"); -@@ -516,15 +517,6 @@ function renderWorkspace() { - if (elements.currentUserRoleInput) { - elements.currentUserRoleInput.value = currentMember?.role || "Viewer"; - } -- if (elements.gameJourneyLink) { -- if (activeGame) { -- elements.gameJourneyLink.href = `toolbox/game-journey/index.html?game=${encodeURIComponent(activeGame.id)}`; -- elements.gameJourneyLink.setAttribute("aria-disabled", "false"); -- } else { -- elements.gameJourneyLink.href = "toolbox/game-journey/index.html?game=none"; -- elements.gameJourneyLink.setAttribute("aria-disabled", "true"); -- } -- } - - renderGameList(progress); - renderMembersTable(activeGame); -@@ -546,9 +538,9 @@ elements.form?.addEventListener("submit", (event) => { - status: elements.gameStatusInput?.value, - }); - -- if (reportRepositoryError(game, "Create Game") || !isRecord(game) || !String(game.name || "").trim()) { -+ if (reportRepositoryError(game, "Add game") || !isRecord(game) || !String(game.name || "").trim()) { - if (!isRepositoryErrorResult(game)) { -- setStatusLog("Create Game could not be completed. Refresh the page or try again shortly."); -+ setStatusLog("Add game could not be completed. Refresh the page or try again shortly."); - } - renderWorkspace(); - return; -@@ -579,7 +571,7 @@ elements.gameList?.addEventListener("click", (event) => { - const game = repository.openGame(button.dataset.gameOpen); - - if (game) { -- setStatusLog(`Opened ${game.name}.`); -+ setStatusLog(`Editing ${game.name}.`); - renderWorkspace(); - } - }); -diff --git a/toolbox/game-hub/index.html b/toolbox/game-hub/index.html -index b2da4cb57..d7d7017f5 100644 ---- a/toolbox/game-hub/index.html -+++ b/toolbox/game-hub/index.html -@@ -28,35 +28,30 @@ -
Review games in the parent table, then expand a game row to see Source Idea and Readiness Output.
-