diff --git a/docs_build/dev/reports/PR_26174_ALFA_010-game-hub-source-idea-child-table-polish-branch-validation.txt b/docs_build/dev/reports/PR_26174_ALFA_010-game-hub-source-idea-child-table-polish-branch-validation.txt new file mode 100644 index 000000000..bc01c2101 --- /dev/null +++ b/docs_build/dev/reports/PR_26174_ALFA_010-game-hub-source-idea-child-table-polish-branch-validation.txt @@ -0,0 +1,6 @@ +Branch Validation: PASS + +PASS - Current branch: pr/26174-ALFA-010-game-hub-source-idea-child-table-polish. +PASS - Stack base: pr/26174-ALFA-009-game-hub-parent-child-table-layout. +PASS - Changes are scoped to Source Idea child table rendering, targeted tests, and required reports. +PASS - No merge to main performed. diff --git a/docs_build/dev/reports/PR_26174_ALFA_010-game-hub-source-idea-child-table-polish-manual-validation-notes.txt b/docs_build/dev/reports/PR_26174_ALFA_010-game-hub-source-idea-child-table-polish-manual-validation-notes.txt new file mode 100644 index 000000000..161a3d220 --- /dev/null +++ b/docs_build/dev/reports/PR_26174_ALFA_010-game-hub-source-idea-child-table-polish-manual-validation-notes.txt @@ -0,0 +1,6 @@ +Manual Validation Notes: PASS + +PASS - Confirmed the Idea Board-created Lantern Reef project expands in Game Hub. +PASS - Confirmed Source Idea child table shows Idea, Pitch, and Note 1 rows. +PASS - Confirmed Source Idea child table has no input, textarea, select, or button controls. +PASS - Confirmed source details still come from the existing Game Hub project record contract. diff --git a/docs_build/dev/reports/PR_26174_ALFA_010-game-hub-source-idea-child-table-polish-requirement-checklist.txt b/docs_build/dev/reports/PR_26174_ALFA_010-game-hub-source-idea-child-table-polish-requirement-checklist.txt new file mode 100644 index 000000000..185081aa4 --- /dev/null +++ b/docs_build/dev/reports/PR_26174_ALFA_010-game-hub-source-idea-child-table-polish-requirement-checklist.txt @@ -0,0 +1,9 @@ +Requirement Checklist: PASS + +PASS - Source Idea appears as a child table under the game parent row. +PASS - Source Idea includes source idea details. +PASS - Source Idea includes notes as read-only child/context rows where data supports it. +PASS - Source Idea is read-only. +PASS - No edit/delete controls for source idea context. +PASS - Creator-facing labels are clear and non-technical. +PASS - Existing API/service contract is preserved. diff --git a/docs_build/dev/reports/PR_26174_ALFA_010-game-hub-source-idea-child-table-polish-validation-lane.txt b/docs_build/dev/reports/PR_26174_ALFA_010-game-hub-source-idea-child-table-polish-validation-lane.txt new file mode 100644 index 000000000..b2926560a --- /dev/null +++ b/docs_build/dev/reports/PR_26174_ALFA_010-game-hub-source-idea-child-table-polish-validation-lane.txt @@ -0,0 +1,3 @@ +Validation Lane: PASS + +PASS - npx playwright test tests/playwright/tools/IdeaBoardTableNotes.spec.mjs -g "Idea Board uses accordion table ideas and notes" diff --git a/docs_build/dev/reports/PR_26174_ALFA_010-game-hub-source-idea-child-table-polish.md b/docs_build/dev/reports/PR_26174_ALFA_010-game-hub-source-idea-child-table-polish.md new file mode 100644 index 000000000..7a430f990 --- /dev/null +++ b/docs_build/dev/reports/PR_26174_ALFA_010-game-hub-source-idea-child-table-polish.md @@ -0,0 +1,16 @@ +# PR_26174_ALFA_010-game-hub-source-idea-child-table-polish + +## Purpose + +Make Source Idea a dedicated child table under the expanded game row. + +## Summary + +- Added a Source Idea child table to expanded Game Hub parent rows. +- Displays source idea, pitch, and read-only source note rows when data is present. +- Kept source idea context free of edit/delete controls. +- Preserved the existing Local API/service contract and source idea normalization. + +## Validation + +PASS - `npx playwright test tests/playwright/tools/IdeaBoardTableNotes.spec.mjs -g "Idea Board uses accordion table ideas and notes"` diff --git a/docs_build/dev/reports/codex_changed_files.txt b/docs_build/dev/reports/codex_changed_files.txt index c4c8e6cf9..6353fc8be 100644 --- a/docs_build/dev/reports/codex_changed_files.txt +++ b/docs_build/dev/reports/codex_changed_files.txt @@ -1,9 +1,9 @@ toolbox/game-hub/game-hub.js -tests/playwright/tools/GameHubMockRepository.spec.mjs +tests/playwright/tools/IdeaBoardTableNotes.spec.mjs docs_build/dev/reports/codex_review.diff docs_build/dev/reports/codex_changed_files.txt -docs_build/dev/reports/PR_26174_ALFA_009-game-hub-parent-child-table-layout.md -docs_build/dev/reports/PR_26174_ALFA_009-game-hub-parent-child-table-layout-branch-validation.txt -docs_build/dev/reports/PR_26174_ALFA_009-game-hub-parent-child-table-layout-requirement-checklist.txt -docs_build/dev/reports/PR_26174_ALFA_009-game-hub-parent-child-table-layout-validation-lane.txt -docs_build/dev/reports/PR_26174_ALFA_009-game-hub-parent-child-table-layout-manual-validation-notes.txt +docs_build/dev/reports/PR_26174_ALFA_010-game-hub-source-idea-child-table-polish.md +docs_build/dev/reports/PR_26174_ALFA_010-game-hub-source-idea-child-table-polish-branch-validation.txt +docs_build/dev/reports/PR_26174_ALFA_010-game-hub-source-idea-child-table-polish-requirement-checklist.txt +docs_build/dev/reports/PR_26174_ALFA_010-game-hub-source-idea-child-table-polish-validation-lane.txt +docs_build/dev/reports/PR_26174_ALFA_010-game-hub-source-idea-child-table-polish-manual-validation-notes.txt diff --git a/docs_build/dev/reports/codex_review.diff b/docs_build/dev/reports/codex_review.diff index 8b90ad570..d241bee0b 100644 --- a/docs_build/dev/reports/codex_review.diff +++ b/docs_build/dev/reports/codex_review.diff @@ -1,195 +1,116 @@ -diff --git a/tests/playwright/tools/GameHubMockRepository.spec.mjs b/tests/playwright/tools/GameHubMockRepository.spec.mjs -index e11631269..695b0a609 100644 ---- a/tests/playwright/tools/GameHubMockRepository.spec.mjs -+++ b/tests/playwright/tools/GameHubMockRepository.spec.mjs -@@ -264,10 +264,32 @@ test("Game Hub creates, opens, and deletes mock games", async ({ page }) => { - await expect(page.locator("[data-game-list]")).toContainText("Gravity Demo"); - await expect(page.locator("[data-game-list]")).toContainText("Collision Demo"); - await expect(page.locator("[data-game-list]")).toContainText("Camera Follow Demo"); -+ await expect(page.locator("[data-game-parent-table='open-games']")).toHaveAttribute("aria-label", "Open Games"); -+ await expect(page.locator("[data-game-parent-table='open-games'] caption")).toHaveText("Open Games"); -+ await expect(page.locator("[data-game-parent-table='open-games'] thead th")).toHaveText([ -+ "Game", -+ "Purpose", -+ "Status", -+ "Owner", -+ "Actions", +diff --git a/tests/playwright/tools/IdeaBoardTableNotes.spec.mjs b/tests/playwright/tools/IdeaBoardTableNotes.spec.mjs +index 722595ae9..f861f1f44 100644 +--- a/tests/playwright/tools/IdeaBoardTableNotes.spec.mjs ++++ b/tests/playwright/tools/IdeaBoardTableNotes.spec.mjs +@@ -392,6 +392,18 @@ test("Idea Board uses accordion table ideas and notes", async ({ page }) => { + await expect(page.locator("[data-source-idea-notes]")).toContainText("Use dusk tide changes as the first Game Hub planning note."); + await expect(page.locator("[data-source-idea-section] :is(input, textarea, select, button)")).toHaveCount(0); + await expect(page.getByRole("button", { name: "Delete Open Game" })).toHaveCount(0); ++ const activeGameRow = page.locator("[data-game-row][data-game-active='true']"); ++ await expect(activeGameRow).toContainText("Lantern Reef"); ++ await activeGameRow.locator("[data-game-toggle]").click(); ++ const sourceIdeaChildTable = page.locator("[data-game-expanded-row] [data-game-child-table='source-idea']"); ++ await expect(sourceIdeaChildTable.locator("caption")).toHaveText("Source Idea"); ++ await expect(sourceIdeaChildTable.locator("thead th")).toHaveText(["Context", "Details"]); ++ await expect(sourceIdeaChildTable.locator("tbody tr")).toHaveText([ ++ "IdeaLantern Reef", ++ "PitchGuide light through a reef that rearranges at dusk.", ++ "Note 1Use dusk tide changes as the first Game Hub planning note.", + ]); - const demoGameRow = page.locator("[data-game-row='demo-game']"); - 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 demoGameRow.locator("[data-game-toggle='demo-game']").click(); -+ await expect(demoGameRow.locator("[data-game-toggle='demo-game']")).toHaveAttribute("aria-expanded", "true"); -+ await expect(page.locator("[data-game-row='demo-game'] + [data-game-expanded-row='demo-game']")).toHaveCount(1); -+ await expect(page.locator("[data-game-expanded-row='demo-game'] [data-game-child-table='summary']")).toContainText("Game Summary"); -+ await expect(page.locator("[data-game-expanded-row='demo-game'] [data-game-child-table='summary'] tbody tr")).toHaveText([ -+ "ProjectDemo Game", -+ "PurposeGame", -+ "StatusUnder Construction", -+ "OwnerUser 1", -+ ]); -+ await demoGameRow.locator("[data-game-toggle='demo-game']").click(); -+ 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 expect(sourceIdeaChildTable.locator(":is(input, textarea, select, button)")).toHaveCount(0); + await page.reload({ waitUntil: "networkidle" }); + await expect(page.locator("[data-active-game-name]")).toHaveText("Lantern Reef"); + await expect(page.locator("[data-game-list]")).toContainText("Lantern Reef"); diff --git a/toolbox/game-hub/game-hub.js b/toolbox/game-hub/game-hub.js -index 2d6f321e4..121e82562 100644 +index 121e82562..67f56ca41 100644 --- a/toolbox/game-hub/game-hub.js +++ b/toolbox/game-hub/game-hub.js -@@ -39,6 +39,10 @@ const elements = { - tableCounts: document.querySelector("[data-game-table-counts]"), - }; - -+const state = { -+ expandedGameId: "", -+}; -+ - function setText(element, value) { - if (element && typeof element.forEach === "function" && !element.nodeType) { - element.forEach((item) => { -@@ -225,6 +229,90 @@ function createGameListStatus(message, state) { - return emptyState; +@@ -271,6 +271,54 @@ function renderGameSummaryChildTable(parent, game) { + parent.append(wrapper); } -+function createCell(value, tagName = "td") { -+ const cell = document.createElement(tagName); -+ cell.textContent = value; -+ return cell; ++function gameSourceIdeaDetails(game) { ++ const sourceIdea = isRecord(game?.sourceIdea) ? game.sourceIdea : null; ++ const name = String(sourceIdea?.idea || "").trim(); ++ const pitch = String(sourceIdea?.pitch || "").trim(); ++ const notes = Array.isArray(sourceIdea?.notes) ++ ? sourceIdea.notes.map((note) => String(note || "").trim()).filter(Boolean) ++ : []; ++ return { ++ name, ++ notes, ++ pitch, ++ }; +} + -+function createGameToggleButton(game, expanded) { -+ const button = document.createElement("button"); -+ button.className = expanded ? "btn btn--compact primary" : "btn btn--compact"; -+ button.type = "button"; -+ button.dataset.gameToggle = game.id; -+ button.setAttribute("aria-expanded", String(expanded)); -+ button.setAttribute("aria-controls", `game-child-${game.id}`); -+ button.textContent = game.name; -+ return button; -+} -+ -+function renderGameSummaryChildTable(parent, game) { ++function renderSourceIdeaChildTable(parent, game) { ++ const sourceIdea = gameSourceIdeaDetails(game); + const wrapper = document.createElement("div"); + wrapper.className = "table-wrapper"; + const table = document.createElement("table"); + table.className = "data-table data-table--fixed"; -+ table.dataset.gameChildTable = "summary"; -+ table.setAttribute("aria-label", `${game.name} game summary`); -+ table.innerHTML = "Game SummaryFieldValue"; ++ table.dataset.gameChildTable = "source-idea"; ++ table.setAttribute("aria-label", `${game.name} source idea`); ++ table.innerHTML = "Source IdeaContextDetails"; + const body = document.createElement("tbody"); + [ -+ ["Project", game.name], -+ ["Purpose", game.purpose], -+ ["Status", game.status], -+ ["Owner", game.ownerDisplayName], ++ ["Idea", sourceIdea.name || "No source idea yet"], ++ ["Pitch", sourceIdea.pitch || "Create a project from Idea Board to see source details."], + ].forEach(([label, value]) => { + const row = document.createElement("tr"); -+ row.append(createCell(label, "th"), createCell(value || "Not set")); ++ row.append(createCell(label, "th"), createCell(value)); ++ row.firstElementChild.scope = "row"; ++ body.append(row); ++ }); ++ ++ const notes = sourceIdea.notes.length ? sourceIdea.notes : ["No source notes."]; ++ notes.forEach((note, index) => { ++ const row = document.createElement("tr"); ++ row.dataset.sourceIdeaNoteRow = String(index + 1); ++ row.append(createCell(`Note ${index + 1}`, "th"), createCell(note)); + row.firstElementChild.scope = "row"; + body.append(row); + }); ++ + table.append(body); + wrapper.append(table); + parent.append(wrapper); +} + -+function renderExpandedGameRow(tbody, game) { -+ const row = document.createElement("tr"); -+ row.dataset.gameExpandedRow = game.id; -+ row.id = `game-child-${game.id}`; -+ const content = document.createElement("td"); -+ content.colSpan = 5; -+ const stack = document.createElement("div"); -+ stack.className = "content-stack content-stack--compact"; -+ renderGameSummaryChildTable(stack, game); -+ content.append(stack); -+ row.append(content); -+ tbody.append(row); -+} -+ -+function renderGameParentRow(tbody, game, activeGame) { -+ const expanded = state.expandedGameId === game.id; -+ const row = document.createElement("tr"); -+ row.dataset.gameRow = game.id; -+ if (activeGame?.id === game.id) { -+ row.dataset.gameActive = "true"; -+ } -+ -+ const nameCell = document.createElement("th"); -+ nameCell.scope = "row"; -+ nameCell.append(createGameToggleButton(game, expanded)); -+ row.append( -+ nameCell, -+ createCell(game.purpose || "Game"), -+ createCell(game.status || "No status"), -+ createCell(game.ownerDisplayName || "No owner"), -+ ); -+ -+ const actions = document.createElement("td"); -+ actions.append(createGameButton(game, activeGame?.id === game.id)); -+ row.append(actions); -+ tbody.append(row); -+ -+ if (expanded) { -+ renderExpandedGameRow(tbody, game); -+ } -+} -+ - function renderProjectInformation(activeGame, currentMember, progress) { - if (!elements.projectRecordsTable) { - return; -@@ -276,25 +364,18 @@ function renderGameList() { - return; - } - -- listResult.forEach((game) => { -- const row = document.createElement("article"); -- row.className = "callout"; -- row.dataset.gameRow = game.id; -- -- const title = document.createElement("h4"); -- title.textContent = game.name; -- -- const meta = document.createElement("p"); -- meta.className = "eyebrow"; -- meta.textContent = `${game.purpose} | ${game.status} | ${game.ownerDisplayName}`; -- -- const isActive = activeGame?.id === game.id; -- const action = createGameButton(game, isActive); -- -- row.append(title, meta, action); -- -- elements.gameList.append(row); -- }); -+ const wrapper = document.createElement("div"); -+ wrapper.className = "table-wrapper"; -+ const table = document.createElement("table"); -+ table.className = "data-table data-table--fixed"; -+ table.dataset.gameParentTable = "open-games"; -+ table.setAttribute("aria-label", "Open Games"); -+ table.innerHTML = "Open GamesGamePurposeStatusOwnerActions"; -+ const body = document.createElement("tbody"); -+ listResult.forEach((game) => renderGameParentRow(body, game, activeGame)); -+ table.append(body); -+ wrapper.append(table); -+ elements.gameList.append(wrapper); + function renderExpandedGameRow(tbody, game) { + const row = document.createElement("tr"); + row.dataset.gameExpandedRow = game.id; +@@ -280,6 +328,7 @@ function renderExpandedGameRow(tbody, game) { + const stack = document.createElement("div"); + stack.className = "content-stack content-stack--compact"; + renderGameSummaryChildTable(stack, game); ++ renderSourceIdeaChildTable(stack, game); + content.append(stack); + row.append(content); + tbody.append(row); +@@ -443,20 +492,15 @@ function renderTableCounts() { } - function renderMembersTable(activeGame) { -@@ -471,6 +552,13 @@ elements.form?.addEventListener("submit", (event) => { - }); + function renderSourceIdea(activeGame) { +- const sourceIdea = isRecord(activeGame?.sourceIdea) ? activeGame.sourceIdea : null; +- const name = String(sourceIdea?.idea || "").trim(); +- const pitch = String(sourceIdea?.pitch || "").trim(); +- const notes = Array.isArray(sourceIdea?.notes) +- ? sourceIdea.notes.map((note) => String(note || "").trim()).filter(Boolean) +- : []; ++ const sourceIdea = gameSourceIdeaDetails(activeGame); - elements.gameList?.addEventListener("click", (event) => { -+ const toggle = event.target.closest("[data-game-toggle]"); -+ if (toggle) { -+ state.expandedGameId = state.expandedGameId === toggle.dataset.gameToggle ? "" : toggle.dataset.gameToggle; -+ renderWorkspace(); -+ return; -+ } -+ - const button = event.target.closest("[data-game-open]"); +- setText(elements.sourceIdeaName, name || "No source idea yet"); +- setText(elements.sourceIdeaDisplay, name || "No source idea yet"); +- setText(elements.sourceIdeaPitch, pitch || "Create a project from Idea Board to see source details."); ++ setText(elements.sourceIdeaName, sourceIdea.name || "No source idea yet"); ++ setText(elements.sourceIdeaDisplay, sourceIdea.name || "No source idea yet"); ++ setText(elements.sourceIdeaPitch, sourceIdea.pitch || "Create a project from Idea Board to see source details."); - if (!button) { + if (elements.sourceIdeaNotes) { + elements.sourceIdeaNotes.replaceChildren(); +- const visibleNotes = notes.length ? notes : ["No source notes."]; ++ const visibleNotes = sourceIdea.notes.length ? sourceIdea.notes : ["No source notes."]; + visibleNotes.forEach((note) => { + const item = document.createElement("li"); + item.textContent = note; diff --git a/tests/playwright/tools/IdeaBoardTableNotes.spec.mjs b/tests/playwright/tools/IdeaBoardTableNotes.spec.mjs index 722595ae9..f861f1f44 100644 --- a/tests/playwright/tools/IdeaBoardTableNotes.spec.mjs +++ b/tests/playwright/tools/IdeaBoardTableNotes.spec.mjs @@ -392,6 +392,18 @@ test("Idea Board uses accordion table ideas and notes", async ({ page }) => { await expect(page.locator("[data-source-idea-notes]")).toContainText("Use dusk tide changes as the first Game Hub planning note."); await expect(page.locator("[data-source-idea-section] :is(input, textarea, select, button)")).toHaveCount(0); await expect(page.getByRole("button", { name: "Delete Open Game" })).toHaveCount(0); + const activeGameRow = page.locator("[data-game-row][data-game-active='true']"); + await expect(activeGameRow).toContainText("Lantern Reef"); + await activeGameRow.locator("[data-game-toggle]").click(); + const sourceIdeaChildTable = page.locator("[data-game-expanded-row] [data-game-child-table='source-idea']"); + await expect(sourceIdeaChildTable.locator("caption")).toHaveText("Source Idea"); + await expect(sourceIdeaChildTable.locator("thead th")).toHaveText(["Context", "Details"]); + await expect(sourceIdeaChildTable.locator("tbody tr")).toHaveText([ + "IdeaLantern Reef", + "PitchGuide light through a reef that rearranges at dusk.", + "Note 1Use dusk tide changes as the first Game Hub planning note.", + ]); + await expect(sourceIdeaChildTable.locator(":is(input, textarea, select, button)")).toHaveCount(0); await page.reload({ waitUntil: "networkidle" }); await expect(page.locator("[data-active-game-name]")).toHaveText("Lantern Reef"); await expect(page.locator("[data-game-list]")).toContainText("Lantern Reef"); diff --git a/toolbox/game-hub/game-hub.js b/toolbox/game-hub/game-hub.js index 121e82562..67f56ca41 100644 --- a/toolbox/game-hub/game-hub.js +++ b/toolbox/game-hub/game-hub.js @@ -271,6 +271,54 @@ function renderGameSummaryChildTable(parent, game) { parent.append(wrapper); } +function gameSourceIdeaDetails(game) { + const sourceIdea = isRecord(game?.sourceIdea) ? game.sourceIdea : null; + const name = String(sourceIdea?.idea || "").trim(); + const pitch = String(sourceIdea?.pitch || "").trim(); + const notes = Array.isArray(sourceIdea?.notes) + ? sourceIdea.notes.map((note) => String(note || "").trim()).filter(Boolean) + : []; + return { + name, + notes, + pitch, + }; +} + +function renderSourceIdeaChildTable(parent, game) { + const sourceIdea = gameSourceIdeaDetails(game); + const wrapper = document.createElement("div"); + wrapper.className = "table-wrapper"; + const table = document.createElement("table"); + table.className = "data-table data-table--fixed"; + table.dataset.gameChildTable = "source-idea"; + table.setAttribute("aria-label", `${game.name} source idea`); + table.innerHTML = "Source IdeaContextDetails"; + const body = document.createElement("tbody"); + [ + ["Idea", sourceIdea.name || "No source idea yet"], + ["Pitch", sourceIdea.pitch || "Create a project from Idea Board to see source details."], + ].forEach(([label, value]) => { + const row = document.createElement("tr"); + row.append(createCell(label, "th"), createCell(value)); + row.firstElementChild.scope = "row"; + body.append(row); + }); + + const notes = sourceIdea.notes.length ? sourceIdea.notes : ["No source notes."]; + notes.forEach((note, index) => { + const row = document.createElement("tr"); + row.dataset.sourceIdeaNoteRow = String(index + 1); + row.append(createCell(`Note ${index + 1}`, "th"), createCell(note)); + row.firstElementChild.scope = "row"; + body.append(row); + }); + + table.append(body); + wrapper.append(table); + parent.append(wrapper); +} + function renderExpandedGameRow(tbody, game) { const row = document.createElement("tr"); row.dataset.gameExpandedRow = game.id; @@ -280,6 +328,7 @@ function renderExpandedGameRow(tbody, game) { const stack = document.createElement("div"); stack.className = "content-stack content-stack--compact"; renderGameSummaryChildTable(stack, game); + renderSourceIdeaChildTable(stack, game); content.append(stack); row.append(content); tbody.append(row); @@ -443,20 +492,15 @@ function renderTableCounts() { } function renderSourceIdea(activeGame) { - const sourceIdea = isRecord(activeGame?.sourceIdea) ? activeGame.sourceIdea : null; - const name = String(sourceIdea?.idea || "").trim(); - const pitch = String(sourceIdea?.pitch || "").trim(); - const notes = Array.isArray(sourceIdea?.notes) - ? sourceIdea.notes.map((note) => String(note || "").trim()).filter(Boolean) - : []; + const sourceIdea = gameSourceIdeaDetails(activeGame); - setText(elements.sourceIdeaName, name || "No source idea yet"); - setText(elements.sourceIdeaDisplay, name || "No source idea yet"); - setText(elements.sourceIdeaPitch, pitch || "Create a project from Idea Board to see source details."); + setText(elements.sourceIdeaName, sourceIdea.name || "No source idea yet"); + setText(elements.sourceIdeaDisplay, sourceIdea.name || "No source idea yet"); + setText(elements.sourceIdeaPitch, sourceIdea.pitch || "Create a project from Idea Board to see source details."); if (elements.sourceIdeaNotes) { elements.sourceIdeaNotes.replaceChildren(); - const visibleNotes = notes.length ? notes : ["No source notes."]; + const visibleNotes = sourceIdea.notes.length ? sourceIdea.notes : ["No source notes."]; visibleNotes.forEach((note) => { const item = document.createElement("li"); item.textContent = note;