diff --git a/docs_build/dev/reports/PR_26174_ALFA_022-idea-board-status-dropdown-fix_branch-validation.md b/docs_build/dev/reports/PR_26174_ALFA_022-idea-board-status-dropdown-fix_branch-validation.md new file mode 100644 index 000000000..1a48b0637 --- /dev/null +++ b/docs_build/dev/reports/PR_26174_ALFA_022-idea-board-status-dropdown-fix_branch-validation.md @@ -0,0 +1,17 @@ +# Branch Validation + +PR: PR_26174_ALFA_022-idea-board-status-dropdown-fix + +Status: PASS with documented legacy-lane warning + +## Checks + +- PASS: Current branch is `pr/26174-ALFA-022-idea-board-status-dropdown-fix`. +- PASS: Started from the current stacked Alfa branch. +- PASS: No main merge was performed. +- PASS: Work stayed inside the requested Idea Board status dropdown/filter, targeted tests, and required report scope. +- PASS: Generated required reports and ZIP artifact. + +## Warning + +- WARN: The touched Toolbox launch-route check reached the updated Idea Board status option assertions, then failed on the existing `500 /api/game-journey/completion-metrics` request. diff --git a/docs_build/dev/reports/PR_26174_ALFA_022-idea-board-status-dropdown-fix_manual-validation-notes.md b/docs_build/dev/reports/PR_26174_ALFA_022-idea-board-status-dropdown-fix_manual-validation-notes.md new file mode 100644 index 000000000..c1477273b --- /dev/null +++ b/docs_build/dev/reports/PR_26174_ALFA_022-idea-board-status-dropdown-fix_manual-validation-notes.md @@ -0,0 +1,6 @@ +# Manual Validation Notes + +- Confirmed the code has separate editable and filter status option lists. +- Confirmed editable dropdown expectations include only New, Exploring, Refining, and Ready. +- Confirmed filter expectations include New, Exploring, Refining, Ready, Project, and Archived. +- Confirmed the touched launch-route test reached the new status option assertions before the existing completion-metrics warning. diff --git a/docs_build/dev/reports/PR_26174_ALFA_022-idea-board-status-dropdown-fix_report.md b/docs_build/dev/reports/PR_26174_ALFA_022-idea-board-status-dropdown-fix_report.md new file mode 100644 index 000000000..b2ce2c852 --- /dev/null +++ b/docs_build/dev/reports/PR_26174_ALFA_022-idea-board-status-dropdown-fix_report.md @@ -0,0 +1,18 @@ +# PR_26174_ALFA_022-idea-board-status-dropdown-fix + +## Summary + +Split Idea Board status choices into explicit editable and filter option lists. + +## Changes + +- Added `editableStatusOptions` with New, Exploring, Refining, and Ready. +- Added `filterStatusOptions` with New, Exploring, Refining, Ready, Project, and Archived. +- Updated editable status dropdown rendering to use only editable statuses. +- Updated status filter rendering and Select All behavior to use filter statuses. +- Updated targeted Playwright coverage for filter options and editable dropdown options. + +## Notes + +- No unrelated cleanup was performed. +- Project and Archived remain available for filtering but do not appear in editable Status dropdowns. diff --git a/docs_build/dev/reports/PR_26174_ALFA_022-idea-board-status-dropdown-fix_requirements-checklist.md b/docs_build/dev/reports/PR_26174_ALFA_022-idea-board-status-dropdown-fix_requirements-checklist.md new file mode 100644 index 000000000..ec24ec9d5 --- /dev/null +++ b/docs_build/dev/reports/PR_26174_ALFA_022-idea-board-status-dropdown-fix_requirements-checklist.md @@ -0,0 +1,12 @@ +# Requirement Checklist + +- PASS: Created `editableStatusOptions` with New, Exploring, Refining, and Ready. +- PASS: Created `filterStatusOptions` with New, Exploring, Refining, Ready, Project, and Archived. +- PASS: Editable Status dropdown uses `editableStatusOptions`. +- PASS: Status Filter accordion uses `filterStatusOptions`. +- PASS: Project does not appear in editable Status dropdowns. +- PASS: Archived does not appear in editable Status dropdowns. +- PASS: Project remains available for filtering. +- PASS: Archived remains available for filtering. +- PASS: Targeted Playwright tests updated. +- PASS: No unrelated cleanup performed. diff --git a/docs_build/dev/reports/PR_26174_ALFA_022-idea-board-status-dropdown-fix_validation-lane.md b/docs_build/dev/reports/PR_26174_ALFA_022-idea-board-status-dropdown-fix_validation-lane.md new file mode 100644 index 000000000..b76ed2d83 --- /dev/null +++ b/docs_build/dev/reports/PR_26174_ALFA_022-idea-board-status-dropdown-fix_validation-lane.md @@ -0,0 +1,11 @@ +# Validation Lane + +## PASS + +- `node --check toolbox/idea-board/index.js` +- `git diff --check` +- `npx playwright test tests/playwright/tools/IdeaBoardTableNotes.spec.mjs --workers=1` + +## WARN + +- `npx playwright test tests/playwright/tools/ToolboxRoutePages.spec.mjs --workers=1 --grep "Idea Board launches"` reached the updated Idea Board status option assertions, then failed because the page recorded `500 http://127.0.0.1:51166/api/game-journey/completion-metrics`. diff --git a/docs_build/dev/reports/codex_changed_files.txt b/docs_build/dev/reports/codex_changed_files.txt index 3c708756f..10031f5d7 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/IdeaBoardTableNotes.spec.mjs +tests/playwright/tools/IdeaBoardTableNotes.spec.mjs tests/playwright/tools/ToolboxRoutePages.spec.mjs -toolbox/idea-board/index.html toolbox/idea-board/index.js diff --git a/docs_build/dev/reports/codex_review.diff b/docs_build/dev/reports/codex_review.diff index 450a2ca28..f5b1867bc 100644 --- a/docs_build/dev/reports/codex_review.diff +++ b/docs_build/dev/reports/codex_review.diff @@ -1,269 +1,149 @@ -diff --git a/assets/theme-v2/css/tables.css b/assets/theme-v2/css/tables.css -index c39ef19f0..5575ff684 100644 ---- a/assets/theme-v2/css/tables.css -+++ b/assets/theme-v2/css/tables.css -@@ -116,26 +116,26 @@ td { - } - - .idea-board-idea-label { -- display: inline-flex; -- align-items: center; -- gap: .35em; -+ display: inline; - color: inherit; - font: inherit; - line-height: var(--line-height-single); - vertical-align: baseline; -- white-space: nowrap -+ white-space: normal - } - - .idea-board-idea-label__text { -- line-height: var(--line-height-single) -+ overflow-wrap: anywhere; -+ line-height: inherit - } - - .idea-board-idea-chevron { - display: inline-block; - width: 1em; - height: 1em; -- flex: 0 0 1em; -+ margin-right: .35em; - background: currentColor; -+ vertical-align: -0.125em; - -webkit-mask-position: center; - mask-position: center; - -webkit-mask-repeat: no-repeat; -diff --git a/tests/playwright/tools/IdeaBoardTableNotes.spec.mjs b/tests/playwright/tools/IdeaBoardTableNotes.spec.mjs -index 214c0081e..da7800ca0 100644 +diff --git a/tests/playwright/tools/IdeaBoardTableNotes.spec.mjs b/tests/playwright/tools/IdeaBoardTableNotes.spec.mjs +index da7800ca0..61d8fdc68 100644 --- a/tests/playwright/tools/IdeaBoardTableNotes.spec.mjs +++ b/tests/playwright/tools/IdeaBoardTableNotes.spec.mjs -@@ -21,8 +21,6 @@ async function expectIdeaChevron(page, ideaId, iconName) { - const cellStyles = getComputedStyle(cell); - const labelStyles = getComputedStyle(label); - const iconStyles = getComputedStyle(icon); -- const textRect = text.getBoundingClientRect(); -- const iconRect = icon.getBoundingClientRect(); - return { - iconName: icon.dataset.ideaBoardChevronIcon, - labelDisplay: labelStyles.display, -@@ -30,21 +28,19 @@ async function expectIdeaChevron(page, ideaId, iconName) { - iconHeight: Number.parseFloat(iconStyles.height), - fontSize: Number.parseFloat(cellStyles.fontSize), - iconColor: iconStyles.backgroundColor, -- iconBottom: iconRect.bottom, -- iconLeft: iconRect.left, -+ iconBeforeText: Boolean(icon.compareDocumentPosition(text) & Node.DOCUMENT_POSITION_FOLLOWING), -+ iconVerticalAlign: Number.parseFloat(iconStyles.verticalAlign), - textColor: cellStyles.color, -- textBottom: textRect.bottom, -- textLeft: textRect.left, - maskImage: iconStyles.getPropertyValue("-webkit-mask-image") || iconStyles.maskImage, - }; - }, ideaId); - expect(metrics.iconName).toBe(iconName); -- expect(metrics.labelDisplay).toBe("inline-flex"); -+ expect(metrics.labelDisplay).toBe("inline"); - expect(Math.abs(metrics.iconWidth - metrics.fontSize)).toBeLessThanOrEqual(1); - expect(Math.abs(metrics.iconHeight - metrics.fontSize)).toBeLessThanOrEqual(1); - expect(metrics.iconColor).toBe(metrics.textColor); -- expect(metrics.iconLeft).toBeLessThan(metrics.textLeft); -- expect(Math.abs(metrics.iconBottom - metrics.textBottom)).toBeLessThanOrEqual(2); -+ expect(metrics.iconBeforeText).toBe(true); -+ expect(metrics.iconVerticalAlign).toBeLessThan(0); - expect(metrics.maskImage).toContain(iconName); - } +@@ -5,6 +5,10 @@ import { isBrowserExtensionNoise } from "../../helpers/browserExtensionNoise.mjs + import { createGameJourneyCompletionMetricsPostgresClientStub } from "../../helpers/gameJourneyCompletionMetricsPostgresClientStub.mjs"; + import { startRepoServer } from "../../helpers/playwrightRepoServer.mjs"; -@@ -203,7 +199,6 @@ test("Idea Board uses accordion table ideas and notes", async ({ page }) => { - "Idea", - "Pitch", - "Status", -- "Updated", - "Notes", - "Actions", - ]); -@@ -219,6 +214,14 @@ test("Idea Board uses accordion table ideas and notes", async ({ page }) => { ++const EDITABLE_STATUS_OPTIONS = ["New", "Exploring", "Refining", "Ready"]; ++const FILTER_STATUS_OPTIONS = ["New", "Exploring", "Refining", "Ready", "Project", "Archived"]; ++const DEFAULT_VISIBLE_STATUS_OPTIONS = ["New", "Exploring", "Refining", "Ready", "Project"]; ++ + function restoreEnvValue(key, value) { + if (value === undefined) { + delete process.env[key]; +@@ -213,7 +217,7 @@ test("Idea Board uses accordion table ideas and notes", async ({ page }) => { + await expect(statusFilterAccordion.locator("summary")).toHaveText("Status Filter"); await expect(statusFilterAccordion.locator("[data-idea-board-filter-select-all]")).toHaveText("Select All"); await expect(statusFilterAccordion.locator("[data-idea-board-filter-clear-all]")).toHaveText("Clear All"); - await expect(statusFilterAccordion.locator("[data-idea-board-status-filter-option]")).toHaveCount(6); -+ const statusFilterTheme = await statusFilterAccordion.locator("[data-idea-board-status-filter-option][value='New']").evaluate((input) => ({ -+ accentColor: getComputedStyle(input).accentColor, -+ toolGroupColor: getComputedStyle(input.closest(".control-lab")).getPropertyValue("--tool-group-color").trim(), -+ })); -+ expect(statusFilterTheme).toEqual({ -+ accentColor: "rgb(255, 45, 45)", -+ toolGroupColor: "#ff2d2d", -+ }); - await expect(statusFilterAccordion.locator(".idea-board-show-filter__option")).toHaveText([ - "New", - "Exploring", -@@ -242,10 +245,21 @@ test("Idea Board uses accordion table ideas and notes", async ({ page }) => { - await expectIdeaChevron(page, "top-thoughts", "gfs-chevron-down.svg"); - await expect(page.locator("[data-idea-board-idea-row='top-thoughts'] td").nth(0)).toHaveText("Smartest person wins..."); - await expect(page.locator("[data-idea-board-idea-row='top-thoughts'] td").nth(1)).toHaveText("Exploring"); -- await expect(page.locator("[data-idea-board-idea-row='top-thoughts'] td").nth(2)).toHaveText("2026-06-20"); - await expect(page.locator("[data-idea-board-notes-count='top-thoughts']")).toHaveText("3 Notes"); - await expect(page.locator("[data-idea-board-idea-row='top-thoughts'] [data-idea-board-idea-action]")).toHaveText(["Edit", "Delete"]); - await expect(page.locator("[data-idea-board-idea-row='top-thoughts'] [data-idea-board-idea-action='create-project']")).toHaveCount(0); -+ const ideaLabelWrapping = await page.locator("[data-idea-board-idea-row='top-thoughts'] .idea-board-idea-label").evaluate((label) => { -+ const labelStyles = getComputedStyle(label); -+ const textStyles = getComputedStyle(label.querySelector(".idea-board-idea-label__text")); -+ return { -+ overflowWrap: textStyles.overflowWrap, -+ whiteSpace: labelStyles.whiteSpace, -+ }; -+ }); -+ expect(ideaLabelWrapping).toEqual({ -+ overflowWrap: "anywhere", -+ whiteSpace: "normal", -+ }); - - await expect(page.locator("[data-idea-board-idea-row='sky-orchard'] th")).toHaveText("Sky Orchard"); - await expectIdeaChevron(page, "sky-orchard", "gfs-chevron-down.svg"); -@@ -259,6 +273,7 @@ test("Idea Board uses accordion table ideas and notes", async ({ page }) => { - await expect(page.locator("[data-idea-board-expanded-row]")).toHaveCount(0); - await page.locator("[data-idea-board-idea-cell='top-thoughts']").click(); - await expect(page.locator("[data-idea-board-expanded-row='top-thoughts']")).toBeVisible(); -+ await expect(page.locator("[data-idea-board-expanded-row='top-thoughts'] > td")).toHaveAttribute("colspan", "5"); - await expectProductionCopy(page); - await expectIdeaChevron(page, "top-thoughts", "gfs-chevron-up.svg"); - await expect(page.locator("[data-idea-board-idea-row='top-thoughts'] + [data-idea-board-expanded-row='top-thoughts']")).toHaveCount(1); -@@ -320,11 +335,8 @@ test("Idea Board uses accordion table ideas and notes", async ({ page }) => { - "Exploring", - "Refining", - "Ready", +- await expect(statusFilterAccordion.locator("[data-idea-board-status-filter-option]")).toHaveCount(6); ++ await expect(statusFilterAccordion.locator("[data-idea-board-status-filter-option]")).toHaveCount(FILTER_STATUS_OPTIONS.length); + const statusFilterTheme = await statusFilterAccordion.locator("[data-idea-board-status-filter-option][value='New']").evaluate((input) => ({ + accentColor: getComputedStyle(input).accentColor, + toolGroupColor: getComputedStyle(input.closest(".control-lab")).getPropertyValue("--tool-group-color").trim(), +@@ -222,18 +226,11 @@ test("Idea Board uses accordion table ideas and notes", async ({ page }) => { + accentColor: "rgb(255, 45, 45)", + toolGroupColor: "#ff2d2d", + }); +- await expect(statusFilterAccordion.locator(".idea-board-show-filter__option")).toHaveText([ +- "New", +- "Exploring", +- "Refining", +- "Ready", - "Project", - "Archived", - ]); -- await expect(ideaInputRow.locator("td").nth(2)).toHaveText(/\d{4}-\d{2}-\d{2}/); -- await expect(ideaInputRow.locator("td").nth(3)).toHaveText("0 Notes"); -+ await expect(ideaInputRow.locator("td").nth(2)).toHaveText("0 Notes"); +- ]); ++ await expect(statusFilterAccordion.locator(".idea-board-show-filter__option")).toHaveText(FILTER_STATUS_OPTIONS); + const checkedStatuses = await page.locator("[data-idea-board-status-filter-option]:checked").evaluateAll((inputs) => ( + inputs.map((input) => input.value) + )); +- expect(checkedStatuses).toEqual(["New", "Exploring", "Refining", "Ready", "Project"]); ++ expect(checkedStatuses).toEqual(DEFAULT_VISIBLE_STATUS_OPTIONS); + await expect(page.locator("[data-idea-board-status-filter-option][value='Archived']")).not.toBeChecked(); + await expect(page.getByText(/another/i)).toHaveCount(0); + await expect(page.locator("[data-idea-board-notes-chevron]")).toHaveCount(0); +@@ -330,12 +327,7 @@ test("Idea Board uses accordion table ideas and notes", async ({ page }) => { + const ideaInputRow = page.locator("[data-idea-board-idea-input-row]").last(); + await expect(ideaInputRow.locator("[data-idea-board-idea-action]")).toHaveText(["Save", "Cancel"]); + await expect(ideaInputRow.locator("[data-idea-board-idea-status-input]")).toHaveCount(1); +- await expect(ideaInputRow.locator("[data-idea-board-idea-status-input] option")).toHaveText([ +- "New", +- "Exploring", +- "Refining", +- "Ready", +- ]); ++ await expect(ideaInputRow.locator("[data-idea-board-idea-status-input] option")).toHaveText(EDITABLE_STATUS_OPTIONS); + await expect(ideaInputRow.locator("td").nth(2)).toHaveText("0 Notes"); await page.locator("[data-idea-board-idea-input]").fill("Lantern Reef"); await page.locator("[data-idea-board-pitch-input]").fill("Guide light through a reef that rearranges at dusk."); - await page.locator("[data-idea-board-idea-status-input]").selectOption("Refining"); +@@ -355,6 +347,7 @@ test("Idea Board uses accordion table ideas and notes", async ({ page }) => { + await page.locator("[data-idea-board-idea-row='lantern-reef'] [data-idea-board-idea-action='edit']").click(); + await expect(page.locator("[data-idea-board-idea-input-row] [data-idea-board-idea-action]")).toHaveText(["Save", "Cancel"]); + await expect(page.locator("[data-idea-board-idea-status-input]")).toHaveCount(1); ++ await expect(page.locator("[data-idea-board-idea-status-input] option")).toHaveText(EDITABLE_STATUS_OPTIONS); + await page.locator("[data-idea-board-idea-status-input]").selectOption("Ready"); + await page.locator("[data-idea-board-idea-action='save']").click(); + await expect(page.locator("[data-idea-board-idea-row='lantern-reef'] td").nth(1)).toHaveText("Ready"); diff --git a/tests/playwright/tools/ToolboxRoutePages.spec.mjs b/tests/playwright/tools/ToolboxRoutePages.spec.mjs -index de9995354..a2622e969 100644 +index a2622e969..1f2bf6e89 100644 --- a/tests/playwright/tools/ToolboxRoutePages.spec.mjs +++ b/tests/playwright/tools/ToolboxRoutePages.spec.mjs -@@ -120,8 +120,6 @@ async function expectIdeaChevron(page, ideaId, iconName) { - const cellStyles = getComputedStyle(cell); - const labelStyles = getComputedStyle(label); - const iconStyles = getComputedStyle(icon); -- const textRect = text.getBoundingClientRect(); -- const iconRect = icon.getBoundingClientRect(); - return { - iconName: icon.dataset.ideaBoardChevronIcon, - labelDisplay: labelStyles.display, -@@ -129,21 +127,19 @@ async function expectIdeaChevron(page, ideaId, iconName) { - iconHeight: Number.parseFloat(iconStyles.height), - fontSize: Number.parseFloat(cellStyles.fontSize), - iconColor: iconStyles.backgroundColor, -- iconBottom: iconRect.bottom, -- iconLeft: iconRect.left, -+ iconBeforeText: Boolean(icon.compareDocumentPosition(text) & Node.DOCUMENT_POSITION_FOLLOWING), -+ iconVerticalAlign: Number.parseFloat(iconStyles.verticalAlign), - textColor: cellStyles.color, -- textBottom: textRect.bottom, -- textLeft: textRect.left, - maskImage: iconStyles.getPropertyValue("-webkit-mask-image") || iconStyles.maskImage, - }; - }, ideaId); - expect(metrics.iconName).toBe(iconName); -- expect(metrics.labelDisplay).toBe("inline-flex"); -+ expect(metrics.labelDisplay).toBe("inline"); - expect(Math.abs(metrics.iconWidth - metrics.fontSize)).toBeLessThanOrEqual(1); - expect(Math.abs(metrics.iconHeight - metrics.fontSize)).toBeLessThanOrEqual(1); - expect(metrics.iconColor).toBe(metrics.textColor); -- expect(metrics.iconLeft).toBeLessThan(metrics.textLeft); -- expect(Math.abs(metrics.iconBottom - metrics.textBottom)).toBeLessThanOrEqual(2); -+ expect(metrics.iconBeforeText).toBe(true); -+ expect(metrics.iconVerticalAlign).toBeLessThan(0); - expect(metrics.maskImage).toContain(iconName); - } +@@ -4,6 +4,9 @@ import { isBrowserExtensionNoise } from "../../helpers/browserExtensionNoise.mjs + import { startRepoServer } from "../../helpers/playwrightRepoServer.mjs"; + import { workspaceV2CoverageReporter } from "../../helpers/workspaceV2CoverageReporter.mjs"; -@@ -314,14 +310,15 @@ test("Idea Board launches from Toolbox with accordion table notes model", async - sections.map((section) => section.getAttribute("data-idea-board-section")) - )); - expect(ideaBoardSections).toEqual([ -- "Workflow", -+ "Status Filter", - "Status", -+ "Workflow", - "Idea Table", - "Notes Governance", - "Diagnostics", ++const IDEA_BOARD_EDITABLE_STATUS_OPTIONS = ["New", "Exploring", "Refining", "Ready"]; ++const IDEA_BOARD_FILTER_STATUS_OPTIONS = ["New", "Exploring", "Refining", "Ready", "Project", "Archived"]; ++ + const TOOL_ROUTE_SMOKE_CASES = [ + { heading: "Game Journey", route: "/tools/game-journey/index.html" }, + { heading: "Idea Board", route: "/tools/idea-board/index.html" }, +@@ -319,6 +322,8 @@ test("Idea Board launches from Toolbox with accordion table notes model", async ]); await expect(page.locator("[data-idea-board-table]")).toBeVisible(); -- await expect(page.locator("[data-idea-board-table] > thead th[scope='col']")).toHaveText(["Idea", "Pitch", "Status", "Updated", "Notes", "Actions"]); -+ await expect(page.locator("[data-idea-board-table] > thead th[scope='col']")).toHaveText(["Idea", "Pitch", "Status", "Notes", "Actions"]); + await expect(page.locator("[data-idea-board-table] > thead th[scope='col']")).toHaveText(["Idea", "Pitch", "Status", "Notes", "Actions"]); ++ await expect(page.locator("[data-idea-board-status-filter-option]")).toHaveCount(IDEA_BOARD_FILTER_STATUS_OPTIONS.length); ++ await expect(page.locator(".idea-board-show-filter__option")).toHaveText(IDEA_BOARD_FILTER_STATUS_OPTIONS); await expect(page.locator("[data-idea-board-idea-row]")).toHaveCount(3); await expect(page.locator("[data-idea-board-expanded-row]")).toHaveCount(0); await expect(page.locator("[data-idea-board-add-idea]")).toHaveText("Add Idea"); -diff --git a/toolbox/idea-board/index.html b/toolbox/idea-board/index.html -index bf4d9a010..db8b2f2ae 100644 ---- a/toolbox/idea-board/index.html -+++ b/toolbox/idea-board/index.html -@@ -36,7 +36,7 @@ - - - --
-+ - - -