From e59f0fcf36409adb707db185f7cc221011fb3073 Mon Sep 17 00:00:00 2001 From: DavidQ Date: Mon, 22 Jun 2026 22:47:23 -0400 Subject: [PATCH] PR_26174_ALFA_020-game-hub-idea-board-cleanup --- .../backlog/BACKLOG_MASTER.md | 8 ++-- ...ub-idea-board-cleanup_branch-validation.md | 17 +++++++ ...a-board-cleanup_manual-validation-notes.md | 8 ++++ ..._020-game-hub-idea-board-cleanup_report.md | 21 +++++++++ ...ea-board-cleanup_requirements-checklist.md | 13 ++++++ ...-hub-idea-board-cleanup_validation-lane.md | 19 ++++++++ .../dev/reports/codex_changed_files.txt | 16 +++---- docs_build/dev/reports/codex_review.diff | Bin 22260 -> 31541 bytes src/shared/toolbox/tool-metadata-inventory.js | 6 +-- .../BuildPathProgressSimplification.spec.mjs | 25 +++++++---- .../tools/GameHubMockRepository.spec.mjs | 39 +++++----------- .../tools/IdeaBoardTableNotes.spec.mjs | 40 ++++++++--------- .../tools/ToolboxAdminMetadataSsot.spec.mjs | 6 +-- .../tools/ToolboxRoutePages.spec.mjs | 42 +++++++++++------- toolbox/game-hub/game-hub.js | 24 +++++++--- toolbox/game-hub/index.html | 12 ++--- toolbox/idea-board/index.html | 26 +++++------ 17 files changed, 205 insertions(+), 117 deletions(-) create mode 100644 docs_build/dev/reports/PR_26174_ALFA_020-game-hub-idea-board-cleanup_branch-validation.md create mode 100644 docs_build/dev/reports/PR_26174_ALFA_020-game-hub-idea-board-cleanup_manual-validation-notes.md create mode 100644 docs_build/dev/reports/PR_26174_ALFA_020-game-hub-idea-board-cleanup_report.md create mode 100644 docs_build/dev/reports/PR_26174_ALFA_020-game-hub-idea-board-cleanup_requirements-checklist.md create mode 100644 docs_build/dev/reports/PR_26174_ALFA_020-game-hub-idea-board-cleanup_validation-lane.md diff --git a/docs_build/dev/ProjectInstructions/backlog/BACKLOG_MASTER.md b/docs_build/dev/ProjectInstructions/backlog/BACKLOG_MASTER.md index 09cc34579..ec1b46b16 100644 --- a/docs_build/dev/ProjectInstructions/backlog/BACKLOG_MASTER.md +++ b/docs_build/dev/ProjectInstructions/backlog/BACKLOG_MASTER.md @@ -4,17 +4,17 @@ ### Idea -0% Complete — Dream, brainstorm, and explore early game concepts +33% Complete — Dream, brainstorm, and explore early game concepts -- [ ] Alfa - Idea Board +- [x] Alfa - Idea Board - [ ] Alfa - Game Concept Notes - [ ] Alfa - Creator Learning ### Design -0% Complete — Shape the game's story, structure, and systems +17% Complete — Shape the game's story, structure, and systems -- [ ] Alfa - Game Hub +- [x] Alfa - Game Hub - [ ] Alfa - Game Design - [ ] Alfa - Game Configuration - [ ] Alfa - Game Crew diff --git a/docs_build/dev/reports/PR_26174_ALFA_020-game-hub-idea-board-cleanup_branch-validation.md b/docs_build/dev/reports/PR_26174_ALFA_020-game-hub-idea-board-cleanup_branch-validation.md new file mode 100644 index 000000000..e5ddc1933 --- /dev/null +++ b/docs_build/dev/reports/PR_26174_ALFA_020-game-hub-idea-board-cleanup_branch-validation.md @@ -0,0 +1,17 @@ +# Branch Validation + +PR: PR_26174_ALFA_020-game-hub-idea-board-cleanup + +Status: PASS with documented legacy-lane warnings + +## Checks + +- PASS: Current branch is `pr/26174-ALFA-020-game-hub-idea-board-cleanup`. +- PASS: Started from the current stacked Alfa branch. +- PASS: No main merge was performed. +- PASS: Work stayed inside the requested Game Hub, Idea Board, status metadata, backlog, tests, and required report scope. +- PASS: Generated required reports and ZIP artifact. + +## Warnings + +- WARN: Broader legacy Toolbox/Build Path Playwright checks were attempted and failed before reliable PR assertions because dynamic Toolbox controls did not mount in that lane, or the legacy completion-metrics endpoint returned 500. Scoped Game Hub and Idea Board lanes passed. diff --git a/docs_build/dev/reports/PR_26174_ALFA_020-game-hub-idea-board-cleanup_manual-validation-notes.md b/docs_build/dev/reports/PR_26174_ALFA_020-game-hub-idea-board-cleanup_manual-validation-notes.md new file mode 100644 index 000000000..d0a1af5e2 --- /dev/null +++ b/docs_build/dev/reports/PR_26174_ALFA_020-game-hub-idea-board-cleanup_manual-validation-notes.md @@ -0,0 +1,8 @@ +# Manual Validation Notes + +- Confirmed Game Hub no longer shows the Game Crew accordion or Current User Role control. +- Confirmed games without Source Idea context expand directly to Readiness Output only. +- Confirmed source-linked Idea Board projects still show Source Idea and Readiness Output as separate child rows. +- Confirmed Idea Board status filter controls are in the first left-side accordion. +- Confirmed status filter labels include Select All, Clear All, New, Exploring, Refining, Ready, Project, and Archived. +- Confirmed Idea Board and Game Hub completion state in backlog and toolbox metadata. diff --git a/docs_build/dev/reports/PR_26174_ALFA_020-game-hub-idea-board-cleanup_report.md b/docs_build/dev/reports/PR_26174_ALFA_020-game-hub-idea-board-cleanup_report.md new file mode 100644 index 000000000..2fa7984d2 --- /dev/null +++ b/docs_build/dev/reports/PR_26174_ALFA_020-game-hub-idea-board-cleanup_report.md @@ -0,0 +1,21 @@ +# PR_26174_ALFA_020-game-hub-idea-board-cleanup + +## Summary + +Updated Game Hub and Idea Board cleanup items for the Alfa stack. + +## Changes + +- Removed the Game Crew accordion from Game Hub and left the scoped game action surface. +- Stopped rendering the Source Idea child table when a game has no Source Idea context. +- Preserved the Readiness Output child table for expanded game rows. +- Moved Idea Board status filtering into the left-side top accordion. +- Marked Idea Board and Game Hub complete in the Project Instructions backlog. +- Reflected Idea Board and Game Hub completion in DB-backed toolbox metadata. +- Updated impacted Playwright expectations for the new child-row and status-filter behavior. + +## Notes + +- No API/service contract changes were made. +- No browser-owned product data or fallback arrays were added. +- The table-first parent/child pattern remains intact. diff --git a/docs_build/dev/reports/PR_26174_ALFA_020-game-hub-idea-board-cleanup_requirements-checklist.md b/docs_build/dev/reports/PR_26174_ALFA_020-game-hub-idea-board-cleanup_requirements-checklist.md new file mode 100644 index 000000000..56717da72 --- /dev/null +++ b/docs_build/dev/reports/PR_26174_ALFA_020-game-hub-idea-board-cleanup_requirements-checklist.md @@ -0,0 +1,13 @@ +# Requirement Checklist + +- PASS: Removed Game Crew accordion from `/toolbox/game-hub/index.html`. +- PASS: Games without Source Idea no longer render the Source Idea child table. +- PASS: Readiness Output child table is preserved. +- PASS: Idea Board status filter controls moved to the left-side top accordion. +- PASS: Status filter accordion includes Select All, Clear All, New, Exploring, Refining, Ready, Project, and Archived. +- PASS: Idea Board marked complete. +- PASS: Game Hub marked complete. +- PASS: Table-first parent/child pattern preserved. +- PASS: Existing API/service contract preserved. +- PASS: No browser-owned product data added. +- PASS: No silent fallbacks added. diff --git a/docs_build/dev/reports/PR_26174_ALFA_020-game-hub-idea-board-cleanup_validation-lane.md b/docs_build/dev/reports/PR_26174_ALFA_020-game-hub-idea-board-cleanup_validation-lane.md new file mode 100644 index 000000000..5879cc8db --- /dev/null +++ b/docs_build/dev/reports/PR_26174_ALFA_020-game-hub-idea-board-cleanup_validation-lane.md @@ -0,0 +1,19 @@ +# Validation Lane + +## PASS + +- `node --check toolbox/game-hub/game-hub.js` +- `node --check toolbox/idea-board/index.js` +- `node --check src/shared/toolbox/tool-metadata-inventory.js` +- `git diff --check` +- Direct registry status probe: Idea Board and Game Hub release channels are `complete`. +- `npx playwright test tests/playwright/tools/IdeaBoardTableNotes.spec.mjs --workers=1` +- `npx playwright test tests/playwright/tools/GameHubMockRepository.spec.mjs --workers=1 --grep-invert "Toolbox member-role filters"` +- `npx playwright test tests/playwright/tools/GameHubMockRepository.spec.mjs tests/playwright/tools/IdeaBoardTableNotes.spec.mjs --workers=1 --grep "Game Hub creates|Idea Board uses accordion"` + +## WARN + +- `npx playwright test tests/playwright/tools/BuildPathProgressSimplification.spec.mjs --workers=1 --grep "Toolbox removes Progress view|Build Path preserves DB order"` did not complete cleanly in this workspace. The first test did not render the dynamic Build Path table; the second timed out after the page was already unstable. +- `npx playwright test tests/playwright/tools/ToolboxRoutePages.spec.mjs --workers=1 --grep "toolbox status kickers|Build Path status filters"` did not complete cleanly in this workspace. The dynamic Toolbox controls did not mount in one test, and a legacy class assertion failed before the status-count assertions. + +The scoped Game Hub and Idea Board validation lanes passed. diff --git a/docs_build/dev/reports/codex_changed_files.txt b/docs_build/dev/reports/codex_changed_files.txt index eb8500db6..34d6661c7 100644 --- a/docs_build/dev/reports/codex_changed_files.txt +++ b/docs_build/dev/reports/codex_changed_files.txt @@ -1,10 +1,10 @@ -assets/theme-v2/css/tables.css -docs_build/dev/reports/PR_26174_ALFA_019-game-hub-selected-button-and-crew-label.md -docs_build/dev/reports/PR_26174_ALFA_019-game-hub-selected-button-and-crew-label_branch-validation.txt -docs_build/dev/reports/PR_26174_ALFA_019-game-hub-selected-button-and-crew-label_manual-validation-notes.txt -docs_build/dev/reports/PR_26174_ALFA_019-game-hub-selected-button-and-crew-label_requirement-checklist.txt -docs_build/dev/reports/PR_26174_ALFA_019-game-hub-selected-button-and-crew-label_validation-lane.txt -docs_build/dev/reports/codex_changed_files.txt -docs_build/dev/reports/codex_review.diff +docs_build/dev/ProjectInstructions/backlog/BACKLOG_MASTER.md +src/shared/toolbox/tool-metadata-inventory.js +tests/playwright/tools/BuildPathProgressSimplification.spec.mjs tests/playwright/tools/GameHubMockRepository.spec.mjs +tests/playwright/tools/IdeaBoardTableNotes.spec.mjs +tests/playwright/tools/ToolboxAdminMetadataSsot.spec.mjs +tests/playwright/tools/ToolboxRoutePages.spec.mjs toolbox/game-hub/game-hub.js +toolbox/game-hub/index.html +toolbox/idea-board/index.html diff --git a/docs_build/dev/reports/codex_review.diff b/docs_build/dev/reports/codex_review.diff index 46e63d2a1bd148109b800cece3635256336d0232..381730a81d6bb7b5d2345fe30d49053f317d74e3 100644 GIT binary patch literal 31541 zcmeHQ>vG%3a{jNUnBs0qREeO(i$uwhl$B(kT_@hPOVaKprEWXV zJVf3mKk_blfxJS#?zv!aC1}Y`QWgI&L~y2Orl)Vy)7|{9fBz3Jm`;V`+ysemcf4>C ze;6-=nYZKl_dD;R@X!7vc|DJlXgNuOa31fB-O2B>@Mh=i^!y**y#4;ekEfScuP(ZG zo)|x=`$jPL{6EC*;bbxx?u`z+U4POW5BJBtebL+9-5(A&9LIU$95=SNx1T!C@4gex zu+tlfZT|ne?>5AS_~x5$#B0xY@wc=4H{v|JTg?2#7ytRM|0Z5WzI)dZI#SFC(c4Q@;0{d z#UEu~pqbUfWh^ae^{Z6sT zyXANm#J3eKV!Xe8-`Q{&GJqvZde!-6D11JgnEkBA_{LJKaS6DeMr(EPH1BCJA6w*MDR+*Lm2%&orMqLK8OQa zx`KdKr=BO-nFI-aAm$XV6wxB`?;vVKFrNi;>P36e+Z%KsvgG5*yOE+AY@6Q;jcK{u z6w?}0atDf-8iNI%50MxCec(R;7p?~^#Ic3FOKg5H5sMjZuqP7#k3@v?*<&lqst|Wc zyn|Mc4^eP)n=qrsJ7=UG-?_;xv?FiiWdLCxOoIuFfo{C;C*3<{-X}s(>^vPp`Hc?u z{BC#uz#H|ZBX^W#=ckS%8T_eGn9O#2ogSFJhi88%@QR?eTUS!n5ow0^ek?TZK-<_P zqT(<){OKNolFQ1-7 zc@R7At4F-?le0(e-um^{O+|U)RF^6_QIN;lfEmXB;L;c*k2j^QQ^DVr~MyqHuYGeT6Nc z_eO4Vw`|acTcnh#BgKw04Q7cSsU1&u#)#W@N(Qw1qb<-DqYd)aCVpw5&58LaDfEPUl`JndNc|jVyI8K8%*=W zD;IdnT%qYqF$%RN(tq`rr8|R`Rg;z9c0<;|F!vH@4;XXpkGg>n+B~@om(j$BN>q6M zK+g~Q+jRXxghcxOuI1R(yu;k8N^ku zMqzf1)tDY?H3OwghmdkZNV(ytgX4*ja+b8h-o<`IqVDCH#0AuI6vi-kfrSa}s$8j% zBntf`-1u=m5$%s+fpdiXXD>DLN*bjWxtxbMO^}w;6!;^Q9t5MfOqN~{S}jlG*iUSI zSRzpjHe1p%vzuSJH}*&F{r8}Yxo_+skT1zFaTSWoh3`*p_3%W#%w!ftcJJIpyA9gh z62~V3&n{z|g|wp7UPtshV$c!8j@avn{f_A2LvPp&T$b)^xGiaO2=h!SGJThClle?D zV2pp}f{JUxIuDvbtyx#uI?CQ<)&d1p`HZxWk}|$dl+%e6%OV<_2rhi*V+*TjM1(+#LM-kq3f& zO65RHeA?1~T7VxC$&co$Af#y*3X(N@G4T@kM zCQt@x+g;uQhH54WA%Pt@O_C@8`mqTGqYqtZFbj&@_vrC*?k-?fB?j8mPbRmgi{K^B--g1vEWRV~ z#E!cN%wb&v*@+dDib1Y0eth=$GKlE_p(a0vt@|T{od%+3(xsCdtVZf1r6H}D#o;ym z)%8*^9guK1d%uOXWgH6?);mdOXv!bM$?q5bB8&reEv!DH)c4aTlfLIpc1OKkoJ^+s z-tKVU>o+=?tbks79$C?s#6o|MJrDFaOr-*K6u^a;kk`tOJ0e{8b3Ewy;Xx~tD7XWn z*fj<2w-qvk!YAI4j3`ioaJ58u$>7CX49HeC$pu65GdGSQMv}Rqr3|xvKJ+vH)tsCr zo)JDpz~CMk%yjC2G&f>Qa+^AY}I2ZOlXs=bhlV6)~p!PIGi~XOwf;TiY7l; z`TCWch0qYgBohne^9b8C)}%Jh8(sMm|6XhaT8}>HwENxk-Ci`p0IW>-ioI zi_#Vt40k)df!H39ao+!;Z13T)O#6KSHDvflu7c?y32$y@{_!TYbLb5zzML75!N+F- z)bhj9f^HPJ4uldUn(u)uT4Y!msUnprjdgwt9~Nd$XU8lfS*y@+9BA9zTFTfx16R*Y z8X^5s`H<<*ohP^LT_Y2%HL+%Av`%Q&G#gr3%qLL?-U^o%SQI}+@Vzy_8^56g6LGOj z%DFl-Mt05RQY+J8?KPK8Y859p*-&9Ml1NrQGbOaO%PcFLiYQ;7lqyEH*nV9KDrLy* zqEgD)d@m;Mf^Kh8=_}>BI=hfN-jJ8FdbLOSEfdBSDOj*kac6s5tLKv6(JBl1%VD;h zPM>YO<4ucE%jt-Z&uij#_p@GZ*rmORqB zG~Xt*M@TAJ`hs=fL|Rt`6`0wbN+OqIzQ49X9dD8@EmE*Ks;&n*)oSwWR|o#H1?|jT z&L_A4!4-_eZLc_g(#_0)&E}sq3YrY?Bmq-DfVJx>J~LK=VG&D>7bQR?A!JuuMuN82 zqQ+vcB>l1lmXUv1yHsbLn6Ie_(p;T502+v3B5+}wM7ZsN$zZlh%dOBrI=?ij3d`09bRMc5G1(Y#Zeh| zp${Nu=qq&zMD+S;17~+|?gmTnwz&%u${i>j*FKmI#7~^EkhI54ap&KS;aP~tvtXdo z)sp4O+9u7=9Bw5X%vIWN+C6VvtK?xLzvDX$%QuqbPbJ?11wQeij(jH^`q#Zp?q(R` zBW}pz7$*4(>8J~%OZmCIrO<)lq*H#CV*Ey#0pw#Lne}>(lN`K$B?kYsJVD~(>g~gv zF73@{dDE78h5K#X$+MR~^ZqnSD4r+ndrDVtLPg10@2?_v9?vLV!G4L&$beH(Hko(7 zAYKA5R{ij}H1B>)O_6nJ4pAm6oYg|0E5She#wIWFEOeQa^<}i_%%+Q9zEcQYA4# zQi1+8)8}9@2O+!Gp<11Bp(?#J@`F8T5H=}bma;1-3HKy)pZ%7Zs*R`xiu?qHJ{M^= z09c0Isx|+-fTf64E6E_1PnToe(o;ZaWJE}E|Rm)#-2uV ztg!+LdR4;c+`daG!yK`I&4|)=uZ{|6awkeoJ&uEC-`!6X*WMs%v#yuA4;}ZW?sPEl z4!YfbZ#dcAJ?Qz3?n7%~*WQNK_9WKt_xhbau0{B1nX1%LW&@B6gef_pYZsVZD*8CU z_tL-w-IkrG>Tg4HGMS(u6cD)w4oNxw2tu}0QW~z%jFL(qTF@lXpQS?yUzP~^ zxn#vpA-6FuoXos*A9;&h-Kl^`8v_MsJcA1u8UVMZwgo@F-peS(UAMo`!f$VZ5t1JA6dboZxN@A;q(p zEmaO9(_$^}z_rmP=L&~_x&%?PCCN~nYboYZOjOBJjx~M?-~x&zPdM^W=Gxy_BjECy1?%N(VfrZ=P>FiR#Z{o)x=ft0_wveE3k|v0>c7WAhV&Zqm5t zSDaVL&NN9VXmR0BIi%fc#)oR_Gg2Wa{KR^5DsQC_MdIDSylNE}4d4Kxin2(=#HQ z6^^6=>DHyQ_KL$jS%;E$dH(rZKc&SpS}X&bMCQ4DT6*JBaMm2heSd1qCD}jIF_nVW z@al#W^k#ySnVa&9y5dMC&~_PB^Fs7pX?g)yTv}1cr8ATxXoVm}WPWK@|9r=E{!Baw z;-suFj(@_2G>&fq0cCtG%9^r4=_yKbrEAk7x!Ud5j_$DnC1^IpyXKmn+&6e3{quny0a|Uq;oZQM}FeC;tM+rgcLNCO~oNjfBk)8J^+w2X0QrInwn@5wfs`+8$yqOlrnhG@C0`&-Ov2=g(-d=@Q3hj;0@!Jpz+nb! z>rndz#Fzh$5`>zQc}X8d-@U#++#d`N;4}36!^6Y9!QOBk`Ywaqgs{u{5k>FycFA0n z4@1w1WOSXg_&XAskgVO&$%`GF|07T4Im&#B`!InCPIQ~#b_F-xloC9R!n-neZfOR$ z8gl(i-UG^_RYdfEA(J;_^Of0IrI#Bsf>i(00XMf5e;2 zk1w*x#CmdJRV#`ey81cZAw><{&O=*LZ5v`&PWTI_;<}}?t&tJU zdDAL;{XA2^0ZuMDLaGaB@_F$`ox-C(|A3VD_gipG^MUA#4#~qP?JSo?di6gTkfJB97b5R?^V^Ra6`wZW|E4VqEfFeVd_To z?NjW>_8uN~>b`>TEDBDdO|KVGTr2iVr|#Q@4OAr{zNWPHJhcR6fw3oU2-8sx$J#z4 z(1lG|)nUzzIoHLJfUIW&oieS42@fDDns5arHHr|ISEpA$Uw-)E)th%8u3r7)RadXu z*qVAypEkB_BixvvWw=+@gPI=cshHtX2HPOTSo+(UNHXdz1Gs?s746qV{I8~>6;?@R z-+@dBIOtPez!#DA5{H&ea1$nB`?qgD%0%n#7&W(kj%J@scwib8_!~t9QpKO2QJIDc zfXw}b49dX6p30y=LXQPI=XIccSY>ZmP68#Gsw|fhourA!HpZkcOOv=jb{okcCcwXZo=E#W{)RktRu zT}sM1Aa>oi_fFWI!Bi%eV za8Q{6!D_f^!O4_;NY70Vq>BYOUtD&rL3qY0DG}mz>~C$p0l}hRUD~sH zqcjpRWI=@*hO}6}e0)GCzqu*HNP+sYHe3S}tr1k7J;x4fVqP=Jrb6>JJ}1{mjTHG1 zAt}HoZe$J?HiZI$K7U(_@Ji)&shhE|$;IthPqw7}ONELYkFHK_k@A^Zp~ARYn=gSt z0!4b_IXAfsCTh4f*2JYeTrpP=5h*66UzG(<`AEKZfil9#t+7iV8VklU^SA(-X#jnz+O_;0Q&KwVD+lmVT|g{iB{ga`$>Y54Tyn!%2Vt;2>Wysb&mS zzPxrEQYih=9y#vlAuFLwkq1nXU#j#GIhW-1r3`{?(>gll;v61)w&lpv#Hv(QI76m~ zU2)4!jwZq}4lzz#!`%?a*Oqkx&UJy3ON6bW(xiSvF)Ppy)m?FH;QIs&_!}c%-eKBz z)Zc!jFAz)giId_Sl@F}*^;IIUlQtvI6l9M+k?;USHS(J1`aOReOhp^zkS@7)1l_p4 z1iv7rjZwE{d~#}js(W{_jBnekC#q%uM*~lTR#*ukpV3@gNF(g!Ci>?vn73O3@ri8j zDi8^ZKb-^PRL$p@vDuvix7@sGND81N^Wb2Qa#kT9a?_mIJgZ=G;LtxvY1c5f8Lud4R7Je}9iH z2N$)uW}#epITWz`wREF@v^deKQM4u#>YkGSK1v~m$T{yt1F7+wxmT9E`9i3@<2bvf zJ8Xa?j|-}oE6GZR>Z;qxPs-CsSJhyA$^F@>%b8a$piUN;2~@A*vp3$rR*TEe1NX12 zH?Tr%?fWinDqgvh+crwd1spLIzrX?g{%YB3jhkVf<`-!S(QzIE&u^U+K@glHju_7Xf;VJ&hXf;nB16~N8m@xCQ1X+JFdQnK zgDle%DK>cCCI21W_D@I(Q403M(GETlr&a$m?deE_%RJeovi;ExW>+%>8RXzF$LirlFwh-8kOam3>pZR1;kgQs# znIvb7P?Ga;t1N53by6s7A&z8}J!DEnAHhMX3Y`{6C&RyvF@->8=Pjv&r z!_iamb;uTUq@0Ow|<3krC<43H4+oK7TdZLM3}7FTf_3)@yXMap{6=jYQ=Dwxn_D= z6E18+{zdt=6g5v1%<+sCC#p08?SrXS%L%bCMsHD?S^6OmehZxf@`CXPV+BQg=2SI@ z%IwJF-_g#Z0S0(X%X}d%0O`Pn4|`bj2ggY$9Te-Rm9;j0jtX)&Q~0Y?BU#i}$Wl9z z$-I;$mTIN1JR6h2c49Kt)|`tHf{o^FQzT)!%PHjzB6@$6~K^o?U(R`Nt8nUKqdZq3O%P%nA)RE`!WD5|8RrNASEH}Pl8p3Nrqte%N55MJt1ig;HDGPU@@b-0(vLw^-=r5GE>Cn$XQSu!svLjJZrQLOz z%k+Si&oyycOB+wZsg}u2*w~olx|1arYiCGkuqiiHSEX`sB`k*bmE~d+E^WdEbvu8w z^VQA4l+SFNuBkz&jtf*gsry-GA(>&Zyn67s1`~tPqKQnbA#5v(d_3eDK-GK>-oBi; zbHwyh6-oVzoJ%g8q<*cG)*7#1P@7Cs+{j;JGxaAb>~+oUM^srtntB`wscMr@**vAI zx%x6|WzyC-uyc?4V{M+zt=U=PzeMV%nfy(TY}z!tL^q4S`Tkoku@JA3Z8IkW%!?|wKAhx!zurO%O$y868nHuTrg=Rn6D9d*NN z{XW%SE4&SxI&OOlgEseab?_1%X#@r3e0$!~d;KW>O@iQCjz7Agts+Qor9li*E()Xs0 z*ZRlzbYx??!n+6`A~uD76~g;XXp7$G`u?+yFZ2s)bw!JIZ`{Y;f1|;==Gck6YGoWN z!prRZkwzGYyPEGvAGrETV|Fy_vA$cqC%1K;r+pb#^xYOT2m1A@4<+=5O27vP+wsnG z&F2umjdQN*JW|J%{ctnv zPa?(8pYg@ zT%VIT;)&ox_P!M*cEdk(9^Svu8DzVoyBOUT4(mF)(D^<6It~BUk?G_0Jr54$wrMLu zb4NDkf#hpf5{7L$ls=<#dyOGJqV&~RGD?8fKky|~J zpH*2FmyV(*A6Nlw5EhM5X#9DU3UrYp^cky()*#_Fu8_o-WEGM^lemuNw>vtLt~1SC z$ZmYlH&)?D_ZH!!^sVclJB+^U$PVm8`7AW{T~9WEWba`=nztcPRKr^t#%0o_eW95X%C`0Y4{`Q&{)$?d9X zcU_pV)q8@)^bUACg7;J(tj~KL^UOnGeiEsRwFQ2xV<-F|INs?zSZsuU_2DhT_qx*6 zOc&t~x>APzTiyFs*B|NGSbV5>Yr)`u6eaJnCiJ)a(60$s`_z$`Vd_J7tPXUC@@Jw^ zx5stp1+{F1(;l9=l()neEbB(b3CDyPbNgRcLePz2sW#v8i=K^E4NLT}3>V?=k>73M za1bTyI;Fz&2CXEzN&c-B_1B_;W;DlZy%nzxWEpZhQ$+q1q8YKY*%yzbIO}orwEP&B znLN6?kldcjU*b8t!j&fzOIaj=r$*P`NOxcLWenYSoy?^w+2aItAqo(l}pilSOV}^L`;dhF3UM@r?R)O>2nRE$d&2OyDVk5=Tdj7MZFZucx-8E^Nl7t`Fjy9PcIe=RFtl^sW) zkNe(uqmN4+KXbjflqD_4;b-x#j0a~DF77eMMOll4%dRAntO-wYF5VCUVr`cRt7^SU z)dSbdRu8x17_qr_rD}ld)?)Lp8rx(=tkU9MdNh{F$K6v#<5>+k;g*i>%L*@-k3)XR zrK}pbFZ)^cHDp66L#pyT)%KqFfXan=O)Ne!?S=efSHCUtsP6}DwlZW*U_m#JBc_vL zo|p0#-%H}jPFxBe>6m-uQr^- z>Ivhh5$q|ODq_9Ctd(1X#OG=XG=t;0p4FBlQH!+5k*L~gGguL_TDK*@{Z!ZRB4^RQ z9SOo=xRTGpDL-HZ#XZMhUBn~jS$X+t zNh;@qsp>bZKh?PAInemkmK(y~R$Fq6%kg!poTb{+eBf@*qdMzN!~{)wo>O2}ysncI zHs|%?&}_aL<}y@Dp0^ji4w{)CP2To}JX(|Wh;2mx)*~?4|E5TEdRbc>%jK~T zm3Jz*wld*0KKC?vm9$O_u*mq~KgQulotr4?y`q~#$x%Ct!^rB6VytM{oX0wMRT-t* z!D1bb?k{BxIFEIj>#fC}Qn}nRa#~j(a;A|?Z2)Jzn*ozK8ea?w2PFt53Y>naY$2H%>7Wl zio7|Y3V2l>jKg7)pFz_HZ+B9ycep7 z9o_C-zfj#jWy2gb@vi75)o{A8S(l^}`bf2MtB|uIX0k!|G}(CSilsNy`d|m|=?E8_ z%T_s&`_WyoDFV#bi|MeTE0h%zgNn7{+ykF$wS-PPDhRBpJl9ofQmJQ_-oX`hg5Y1M zP|@}NPRBvF8I95%U{9<#H+k0tr^%jN5f%TRayv~)p| z=GiG3z+MD_}6OuZeu<-AVTE%}kOX1peka$ox?>USM2k{_vS zkJAbU-Z%9NJc?cizXMH+@MF(E7X6(UZbMxL9!IWt?{#^tPvJ;W6U22{-f=mz3op+>_pTqS< z$iqhaDc_~|O{CtB@`q1_&xU%_*{Q#$k9Q7nhMduN0H0}0%B|S7SEgdppmO#!mi!<$#==T%(`il&zdy5=b)xTO`ee~-}KM$?nGpTy^yOhPo-*PIHw(? zpNWFs=qx$1RS?hx*3j8c$BOB%{XCa-b=&(+?rM9|+8V`fe0Cba8TLSL=zo$@GUWWp zsopt?%Jq5ZTm^FSclI`!cA#P9{h;i3%10y`uqX6q%}|DWc=YGtb5Z8AfqB>uPv<8! z2K<6m<_6_>P>Pcbo7b2mc}A0ukuy9Gil1Z^ghaEvg5dP=>WB4-T7{-93IVlsk*1Y+ zw?jnnZh6)e#otnIV|_bR-s?|g$9F-)E3ycy_E-glzUaKCHH}7kPGd}sl|@gH(`NM` zXp>XLIv((E>{Ck~uN=L*4L84NvSi)9<^Efu`FxLMexKWS=T37d%Fi-b#`XHL4*<)y z8#Q`#w&oDkqYSia5)0Jp`AF6@r%T!Dxs|TJlL8sJ)Q*rF12Sd1OnonGs)TvZZr#|g zEUA-bHSI3%koNwp#i)`s!)Lx!%Hyz{I*Yv0(Tskk!O7+{)vWEF^(<7UE?dk|Rw%{X z(`TyH*5cD?YV-cbtJ%d-m?l1!eMhs(kK2QvWVeYTZ1?apSuu9}x3f&aee?bJMk&t` zIBK$1Lu7*wB#yAyjGTtvINp3@UiLEj=WiW#e@+kDW$WFP}%q$$lN*YHcCUBZi}1=f2aSu(yo3M<0zt@>oea znriuD!GOOdiXQi-mFix~dHdDs>PKDAP<{8}`^jp!XM^=J`n_s;%+9|(mh4~OYLa8) z(K{Mj{T7Sr$`Tx`_wI;lolPFr?M<@I)mCrXUC(A?)4M40jw`1^ijG+asKz*XjC_V+ z=v$&pvfAU;74jL=yIhFm>&%MenRUjqRli3PE|JNMUco<-SIO7(t)k&?b(`*PdK5K;JuBGvhssc;a#IkDL}4pees`ZF;Oc9@*@@TfjOq z^CKH^C<&lO;=5AIHPr8PjVPL$CT}RT7>KS5?`9<9?S_B$cw=u!V;}WS?02yhH_p<_ z;m@GHK(EJ#-W$_C^xj`+o_jn*ZUuhOjIPxWBZN@>OmMoK@YF$#GWZNz`d6ql`P0#J zuMM&$nD3`IczK&6Z+buqi9@g#CjUeO+c7TiYt{n>oZ row.order)).toEqual([1, 2, 3, 4, 5, 6, 13, 14]); - expect(rows.map((row) => row.releaseChannel)).toEqual(["beta", "beta", "complete", "beta", "beta", "beta", "beta", "beta"]); + expect(rows.map((row) => row.order)).toEqual([1, 2, 3, 3, 4, 5, 6, 13, 14, 38]); + expect(rows.map((row) => row.releaseChannel)).toEqual(["complete", "beta", "complete", "beta", "beta", "beta", "beta", "beta", "beta", "beta"]); expect(rows.every((row) => row.metadataSource === "toolbox_tool_metadata")).toBe(true); await expectNoPageFailures(failures); @@ -164,9 +172,10 @@ test("Build Path tool names link to registered routes and render badge images", try { await page.getByRole("button", { name: "Build Path" }).click(); const rows = page.locator("[data-build-path-table='workflow'] tbody tr"); - await expect(rows).toHaveCount(1); + await expect(rows).not.toHaveCount(0); - const row = rows.first(); + const row = page.locator("[data-build-path-tool='Colors']"); + await expect(row).toHaveCount(1); const toolName = await row.getAttribute("data-build-path-tool"); const registrySnapshot = await fetchApiData(failures.server, "/api/toolbox/registry/snapshot"); const registryToolsByDisplayName = new Map(registrySnapshot.activeTools.map((tool) => [tool.displayName, tool])); diff --git a/tests/playwright/tools/GameHubMockRepository.spec.mjs b/tests/playwright/tools/GameHubMockRepository.spec.mjs index f2dac0710..6f6d046d2 100644 --- a/tests/playwright/tools/GameHubMockRepository.spec.mjs +++ b/tests/playwright/tools/GameHubMockRepository.spec.mjs @@ -258,8 +258,9 @@ test("Game Hub creates, opens, and deletes mock games", async ({ page }) => { 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.locator("summary").filter({ hasText: /^Game Crew$/ })).toHaveCount(1); + await expect(page.locator("summary").filter({ hasText: /^Game Crew$/ })).toHaveCount(0); await expect(page.locator("main")).not.toContainText("game-hub/Game Crew"); + await expect(page.getByLabel("Current User Role")).toHaveCount(0); await expect(page.getByRole("link", { name: "Open Game Journey" })).toHaveCount(0); await expect(page.locator(".tool-center-panel")).not.toContainText("Review games in the parent table"); await expect(page.locator("[data-project-record-status]")).toHaveText("Game table loaded."); @@ -340,13 +341,12 @@ test("Game Hub creates, opens, and deletes mock games", async ({ page }) => { 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']"); - await expect(demoChildRows).toHaveCount(2); - await expect(demoChildRows.nth(0)).toHaveAttribute("data-game-child-row", "source-idea"); - await expect(demoChildRows.nth(1)).toHaveAttribute("data-game-child-row", "readiness-output"); + await expect(demoChildRows).toHaveCount(1); + await expect(demoChildRows.nth(0)).toHaveAttribute("data-game-child-row", "readiness-output"); await expect(page.locator("[data-game-expanded-row='demo-game'] [data-game-child-table='summary']")).toHaveCount(0); - await expect(page.locator("[data-game-expanded-row='demo-game'] [data-game-child-table]")).toHaveCount(2); - await expect(demoChildRows.nth(0).locator("[data-game-child-table='source-idea'] caption")).toHaveText("Source Idea"); - const readinessOutputTable = demoChildRows.nth(1).locator("[data-game-child-table='readiness-output']"); + await expect(page.locator("[data-game-expanded-row='demo-game'] [data-game-child-table]")).toHaveCount(1); + await expect(page.locator("[data-game-expanded-row='demo-game'] [data-game-child-table='source-idea']")).toHaveCount(0); + const readinessOutputTable = demoChildRows.nth(0).locator("[data-game-child-table='readiness-output']"); await expect(readinessOutputTable.locator("caption")).toHaveText("Readiness Output"); await expect(readinessOutputTable.locator("thead th")).toHaveText(["Output", "Status"]); await expect(readinessOutputTable.locator("tbody tr")).toHaveText([ @@ -416,7 +416,8 @@ test("Game Hub creates, opens, and deletes mock games", async ({ page }) => { await expect(page.locator("[data-game-row='archive-game-2'] [data-game-toggle='archive-game-2']")).not.toHaveAttribute("aria-current", "true"); await expect(page.locator("[data-game-toggle][aria-current='true']")).toHaveCount(1); await expect(page.locator("[data-game-toggle][data-game-active='true']")).toHaveCount(1); - await expect(page.locator("[data-game-expanded-row='launch-test-game-1']")).toHaveCount(2); + await expect(page.locator("[data-game-expanded-row='launch-test-game-1']")).toHaveCount(1); + await expect(page.locator("[data-game-expanded-row='launch-test-game-1']")).toHaveAttribute("data-game-child-row", "readiness-output"); await expect(page.locator("[data-game-expanded-row='archive-game-2']")).toHaveCount(0); await expect(page.locator("[data-game-row='launch-test-game-1'] [data-game-toggle='launch-test-game-1']")).toHaveClass("btn btn--compact primary"); await expect(page.locator("[data-game-row='launch-test-game-1']").getByRole("button", { name: "Edit Launch Test Game" })).not.toHaveClass(/primary/); @@ -579,7 +580,7 @@ test("Game Hub preserves guest browsing and blocks guest saves", async ({ page } await expect(page.getByLabel("Game Name")).toHaveCount(0); await expect(page.getByLabel("Game Purpose")).toHaveCount(0); await expect(page.getByLabel("Game Status")).toHaveCount(0); - await expect(page.getByLabel("Current User Role")).toBeDisabled(); + await expect(page.getByLabel("Current User Role")).toHaveCount(0); 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("btn btn--compact primary"); @@ -751,22 +752,11 @@ test("Game Hub reports malformed active-game payloads without throwing", async ( } }); -test("Game Hub displays and edits game purpose and member role", async ({ page }) => { +test("Game Hub displays and edits game purpose", async ({ page }) => { const failures = await openRepoPage(page, "/toolbox/game-hub/index.html", { session: creatorSession() }); try { - await expect(page.locator("#currentUserRoleInput option")).toHaveText([ - "Owner", - "Designer", - "World Builder", - "Artist", - "Audio Creator", - "Translator", - "Tester", - "Publisher", - "Viewer" - ]); - await expect(page.getByLabel("Current User Role")).toHaveValue("Owner"); + await expect(page.getByLabel("Current User Role")).toHaveCount(0); await page.getByRole("button", { name: "Edit Demo Game" }).click(); const editRow = page.locator("[data-game-edit-row='demo-game']"); @@ -792,10 +782,6 @@ test("Game Hub displays and edits game purpose and member role", async ({ page } await expect(page.locator("[data-game-row='demo-game'] td").nth(1)).toHaveText("Ready for Testing"); await expect(page.locator("[data-game-hub-log]")).toHaveText("Saved Demo Game."); - await page.getByLabel("Current User Role").selectOption("Designer"); - await expect(page.getByLabel("Current User Role")).toHaveValue("Designer"); - await expect(page.locator("[data-game-hub-log]")).toHaveText("Updated current user role to Designer."); - await page.getByRole("button", { name: "Add Game" }).click(); const addRow = page.locator("[data-game-add-row='input']"); await addRow.getByLabel("Game").fill("Purpose Review Game"); @@ -804,7 +790,6 @@ test("Game Hub displays and edits game purpose and member role", async ({ page } await expect(page.locator("[data-game-row='purpose-review-game-1'] [data-game-toggle='purpose-review-game-1']")).toHaveClass("btn btn--compact 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"); await expectNoPageFailures(failures); diff --git a/tests/playwright/tools/IdeaBoardTableNotes.spec.mjs b/tests/playwright/tools/IdeaBoardTableNotes.spec.mjs index b1faf33d8..214c0081e 100644 --- a/tests/playwright/tools/IdeaBoardTableNotes.spec.mjs +++ b/tests/playwright/tools/IdeaBoardTableNotes.spec.mjs @@ -212,23 +212,21 @@ test("Idea Board uses accordion table ideas and notes", async ({ page }) => { await expect(page.locator("[data-idea-board-add-idea-row]")).toHaveCount(1); await expect(page.locator("[data-idea-board-add-idea]")).toHaveText("Add Idea"); await expectButtonLeftAligned(page, "[data-idea-board-add-idea]", "[data-idea-board-add-idea-row] > td"); - await expect(page.locator("[data-idea-board-show-filter] summary")).toHaveText("Show"); - const captionMetrics = await page.locator(".idea-board-table-caption").evaluate((caption) => { - const label = caption.querySelector("span"); - const filter = caption.querySelector("[data-idea-board-show-filter]"); - const labelRect = label.getBoundingClientRect(); - const filterRect = filter.getBoundingClientRect(); - return { - filterRight: filterRect.right, - filterTop: filterRect.top, - labelRight: labelRect.right, - labelTop: labelRect.top, - }; - }); - expect(captionMetrics.filterRight).toBeGreaterThan(captionMetrics.labelRight); - expect(Math.abs(captionMetrics.filterTop - captionMetrics.labelTop)).toBeLessThanOrEqual(4); - await page.locator("[data-idea-board-show-filter] summary").click(); - await expect(page.locator("[data-idea-board-status-filter-option]")).toHaveCount(6); + await expect(page.locator(".tool-center-panel [data-idea-board-show-filter]")).toHaveCount(0); + const statusFilterAccordion = page.locator("aside.tool-group-idea").first().locator("[data-idea-board-section='Status Filter']"); + await expect(page.locator("aside.tool-group-idea").first().locator(".accordion-stack > details").first()).toHaveAttribute("data-idea-board-section", "Status Filter"); + 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); + await expect(statusFilterAccordion.locator(".idea-board-show-filter__option")).toHaveText([ + "New", + "Exploring", + "Refining", + "Ready", + "Project", + "Archived", + ]); const checkedStatuses = await page.locator("[data-idea-board-status-filter-option]:checked").evaluateAll((inputs) => ( inputs.map((input) => input.value) )); @@ -393,9 +391,9 @@ test("Idea Board uses accordion table ideas and notes", async ({ page }) => { await expect(page.locator("[data-game-output-panels]")).toHaveCount(0); await expect(page.locator("[data-game-hub-foundation]")).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 activeGameToggle = page.locator("[data-game-toggle][data-game-active='true']"); + await expect(activeGameToggle).toHaveText("Lantern Reef"); + await activeGameToggle.click(); let expandedRows = page.locator("[data-game-expanded-row]"); await expect(expandedRows).toHaveCount(2); await expect(expandedRows.nth(0)).toHaveAttribute("data-game-child-row", "source-idea"); @@ -416,7 +414,7 @@ test("Idea Board uses accordion table ideas and notes", async ({ page }) => { await expect(page.locator("[data-source-idea-section]")).toHaveCount(0); await expect(page.locator("[data-game-output-panels]")).toHaveCount(0); await expect(page.locator("[data-game-hub-foundation]")).toHaveCount(0); - await activeGameRow.locator("[data-game-toggle]").click(); + await activeGameToggle.click(); expandedRows = page.locator("[data-game-expanded-row]"); await expect(expandedRows).toHaveCount(2); sourceIdeaChildTable = expandedRows.nth(0).locator("[data-game-child-table='source-idea']"); diff --git a/tests/playwright/tools/ToolboxAdminMetadataSsot.spec.mjs b/tests/playwright/tools/ToolboxAdminMetadataSsot.spec.mjs index 3743687e9..b138c4ba5 100644 --- a/tests/playwright/tools/ToolboxAdminMetadataSsot.spec.mjs +++ b/tests/playwright/tools/ToolboxAdminMetadataSsot.spec.mjs @@ -244,10 +244,10 @@ test("Toolbox and Admin Tool Votes share the same DB-backed metadata and plannin const counts = countByStatus(snapshot.rows); const visibleCounts = countByStatus(visibleSnapshotRows); expect(counts).toMatchObject({ - beta: 7, - complete: 1, + beta: 6, + complete: 3, planned: 31, - wireframe: 5, + wireframe: 4, deprecated: 2, }); const orderedSetupRows = snapshot.rows diff --git a/tests/playwright/tools/ToolboxRoutePages.spec.mjs b/tests/playwright/tools/ToolboxRoutePages.spec.mjs index 12e463488..de9995354 100644 --- a/tests/playwright/tools/ToolboxRoutePages.spec.mjs +++ b/tests/playwright/tools/ToolboxRoutePages.spec.mjs @@ -510,9 +510,9 @@ test("toolbox status kickers, filters, card order, and voting controls work from await expect(page.locator("[data-toolbox-status-filter]")).toHaveText([ "Planned (28)", - "Wireframe (5)", - "Beta (7)", - "Complete (1)", + "Wireframe (4)", + "Beta (6)", + "Complete (3)", "Deprecated (1)", ]); await expect(page.locator("[data-toolbox-status-filter='planned']")).toHaveAttribute("aria-pressed", "false"); @@ -527,9 +527,9 @@ test("toolbox status kickers, filters, card order, and voting controls work from await page.locator("[data-tools-view='build-path']").click(); await expect(page.locator("[data-toolbox-status-filter]")).toHaveText([ "Planned (28)", - "Wireframe (5)", - "Beta (7)", - "Complete (1)", + "Wireframe (4)", + "Beta (6)", + "Complete (3)", "Deprecated (1)", ]); await expect(page.locator("[data-toolbox-status-filter='planned']")).toHaveAttribute("aria-pressed", "false"); @@ -552,7 +552,7 @@ test("toolbox status kickers, filters, card order, and voting controls work from await page.locator("[data-toolbox-status-filter='deprecated']").click(); await expect(page.locator("[data-toolbox-status-filter='deprecated']")).toHaveAttribute("aria-pressed", "true"); - for (const toolName of ["Assets", "Tags", "Game Configuration", "Game Design", "Game Journey", "Game Hub"]) { + for (const toolName of ["Assets", "Tags", "Game Configuration", "Game Design", "Game Journey"]) { const betaCard = page.locator(`[data-toolbox-tool-card='${toolName}']`); await expect(betaCard).toBeVisible(); await expect(betaCard.locator("[data-toolbox-kicker]")).toHaveText("Beta"); @@ -562,6 +562,16 @@ test("toolbox status kickers, filters, card order, and voting controls work from ); } + for (const toolName of ["Colors", "Game Hub", "Idea Board"]) { + const completeCard = page.locator(`[data-toolbox-tool-card='${toolName}']`); + await expect(completeCard).toBeVisible(); + await expect(completeCard.locator("[data-toolbox-kicker]")).toHaveText("Complete"); + await expect(completeCard.locator("[data-toolbox-kicker]")).toHaveAttribute( + "title", + STATUS_HELP_TEXT.complete, + ); + } + const wireframeCard = page.locator("[data-toolbox-tool-card='Saved Data']"); await expect(wireframeCard).toBeVisible(); await expect(wireframeCard.locator("[data-toolbox-kicker]")).toHaveText("Wireframe"); @@ -816,7 +826,7 @@ test("toolbox status kickers, filters, card order, and voting controls work from await page.goto(`${server.baseUrl}/toolbox/index.html`, { waitUntil: "networkidle" }); await page.locator("[data-tools-view='build-path']").click(); - await expect(page.locator("[data-toolbox-status-filter='complete']")).toHaveText("Complete (0)"); + await expect(page.locator("[data-toolbox-status-filter='complete']")).toHaveText("Complete (2)"); await expect(page.locator("[data-build-path-tool='Colors']")).toHaveCount(0); await page.locator("[data-toolbox-status-filter='beta']").click(); const colorsBuildPathRow = page.locator("[data-build-path-tool='Colors']"); @@ -1235,19 +1245,19 @@ test("toolbox Build Path status filters support multi-select registry-matched to await expect(page.locator("[data-toolbox-status-filter]")).toHaveText([ "Planned (28)", - "Wireframe (5)", - "Beta (7)", - "Complete (1)", + "Wireframe (4)", + "Beta (6)", + "Complete (3)", "Deprecated (1)", ]); await expectActiveFilters(["complete"]); await expect(page.locator("[data-build-path-tool='Colors']")).toBeVisible(); - await expectBuildPathChannels(["complete"], 1); + await expectBuildPathChannels(["complete"], 3); await expectBuildPathOrder("Colors", registryById.get("colors").order); await page.locator("[data-toolbox-status-filter='planned']").click(); await expectActiveFilters(["planned", "complete"]); - await expectBuildPathChannels(["planned", "complete"], 29); + await expectBuildPathChannels(["planned", "complete"], 31); await expect(page.locator("[data-build-path-tool='AI Command Center']")).toBeVisible(); await expectBuildPathOrder("AI Command Center", registryById.get("ai-assistant").order); await expectBuildPathOrder("Colors", registryById.get("colors").order); @@ -1260,19 +1270,19 @@ test("toolbox Build Path status filters support multi-select registry-matched to await page.locator("[data-toolbox-status-filter='wireframe']").click(); await expectActiveFilters(["planned", "wireframe"]); - await expectBuildPathChannels(["planned", "wireframe"], 33); + await expectBuildPathChannels(["planned", "wireframe"], 32); await expect(page.locator("[data-build-path-tool='Saved Data']")).toBeVisible(); await expect(page.locator("[data-build-path-tool='Build Game']")).toHaveCount(0); await page.locator("[data-toolbox-status-filter='deprecated']").click(); await expectActiveFilters(["planned", "wireframe", "deprecated"]); - await expectBuildPathChannels(["planned", "wireframe", "deprecated"], 34); + await expectBuildPathChannels(["planned", "wireframe", "deprecated"], 33); await expect(page.locator("[data-build-path-tool='Build Game']")).toBeVisible(); await expectBuildPathOrder("Build Game", registryById.get("build-game").order); await page.locator("[data-toolbox-status-filter='beta']").click(); await expectActiveFilters(["planned", "wireframe", "beta", "deprecated"]); - await expectBuildPathChannels(["planned", "wireframe", "beta", "deprecated"], 41); + await expectBuildPathChannels(["planned", "wireframe", "beta", "deprecated"], 39); expect(failedRequests).toEqual([]); expect(pageErrors).toEqual([]); diff --git a/toolbox/game-hub/game-hub.js b/toolbox/game-hub/game-hub.js index 71e7a511d..b04c26882 100644 --- a/toolbox/game-hub/game-hub.js +++ b/toolbox/game-hub/game-hub.js @@ -275,7 +275,12 @@ function createGameToggleButton(game, expanded, active) { button.setAttribute("aria-current", "true"); } button.setAttribute("aria-expanded", String(expanded)); - button.setAttribute("aria-controls", `game-child-source-idea-${game.id} game-child-readiness-output-${game.id}`); + const controlledRows = []; + if (hasSourceIdeaDetails(game)) { + controlledRows.push(`game-child-source-idea-${game.id}`); + } + controlledRows.push(`game-child-readiness-output-${game.id}`); + button.setAttribute("aria-controls", controlledRows.join(" ")); button.textContent = game.name; return button; } @@ -294,6 +299,11 @@ function gameSourceIdeaDetails(game) { }; } +function hasSourceIdeaDetails(game) { + const sourceIdea = gameSourceIdeaDetails(game); + return Boolean(sourceIdea.name || sourceIdea.pitch || sourceIdea.notes.length); +} + function renderSourceIdeaChildTable(parent, game) { const sourceIdea = gameSourceIdeaDetails(game); const wrapper = document.createElement("div"); @@ -375,18 +385,22 @@ function renderReadinessOutputChildTable(parent, game, progress, active) { } function renderExpandedGameRow(tbody, game, progress, active) { - [ - { + const childRows = []; + if (hasSourceIdeaDetails(game)) { + childRows.push({ id: `game-child-source-idea-${game.id}`, render: (parent) => renderSourceIdeaChildTable(parent, game), type: "source-idea", - }, + }); + } + childRows.push( { id: `game-child-readiness-output-${game.id}`, render: (parent) => renderReadinessOutputChildTable(parent, game, progress, active), type: "readiness-output", }, - ].forEach(({ id, render, type }) => { + ); + childRows.forEach(({ id, render, type }) => { const row = document.createElement("tr"); row.dataset.gameExpandedRow = game.id; row.dataset.gameChildRow = type; diff --git a/toolbox/game-hub/index.html b/toolbox/game-hub/index.html index c313eeb7a..0b34801e9 100644 --- a/toolbox/game-hub/index.html +++ b/toolbox/game-hub/index.html @@ -26,16 +26,10 @@

Game Hub

diff --git a/toolbox/idea-board/index.html b/toolbox/idea-board/index.html index 5734f4703..bf4d9a010 100644 --- a/toolbox/idea-board/index.html +++ b/toolbox/idea-board/index.html @@ -29,10 +29,14 @@

Idea Board

Idea Filters

-
- Workflow +
+ Status Filter
-

Review ideas in the table, then expand an idea row to manage its notes.

+
+ + +
+
@@ -41,6 +45,12 @@

Idea Filters

Use status to show where each idea stands: New, Exploring, Refining, Ready, Project, or Archived.

+
+ Workflow +
+

Review ideas in the table, then expand an idea row to manage its notes.

+
+
@@ -49,16 +59,6 @@

Ideas

Scan, compare, and update early ideas.

Idea Board table with expandable notes rows -
- Show -
-
- - -
-
-
-