@webpieces/nx-webpieces-rules 0.4.947 → 0.4.949
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +20 -11
- package/package.json +7 -7
- package/src/index.d.ts +1 -1
- package/src/index.js +3 -1
- package/src/index.js.map +1 -1
- package/src/lib/graph-color-modes.d.ts +18 -12
- package/src/lib/graph-color-modes.js +18 -20
- package/src/lib/graph-color-modes.js.map +1 -1
- package/src/lib/graph-legend.d.ts +11 -3
- package/src/lib/graph-legend.js +25 -9
- package/src/lib/graph-legend.js.map +1 -1
- package/src/lib/graph-mode-state.client.d.ts +2 -1
- package/src/lib/graph-mode-state.client.js +3 -1
- package/src/lib/graph-mode-state.client.js.map +1 -1
- package/src/lib/graph-page-shell.js +2 -2
- package/src/lib/graph-page-shell.js.map +1 -1
- package/src/lib/graph-page-styles.js +4 -1
- package/src/lib/graph-page-styles.js.map +1 -1
- package/src/lib/graph-product-paint.client.d.ts +92 -0
- package/src/lib/graph-product-paint.client.js +196 -0
- package/src/lib/graph-product-paint.client.js.map +1 -0
- package/src/lib/graph-products.d.ts +54 -6
- package/src/lib/graph-products.js +62 -9
- package/src/lib/graph-products.js.map +1 -1
- package/src/lib/graph-render-model.d.ts +12 -12
- package/src/lib/graph-render-model.js +12 -14
- package/src/lib/graph-render-model.js.map +1 -1
- package/src/lib/graph-visualizer.client.d.ts +13 -1
- package/src/lib/graph-visualizer.client.js +27 -4
- package/src/lib/graph-visualizer.client.js.map +1 -1
- package/src/lib/graph-visualizer.d.ts +3 -3
- package/src/lib/graph-visualizer.js +13 -12
- package/src/lib/graph-visualizer.js.map +1 -1
- package/src/lib/runtime-goal-comparison.js +1 -1
- package/src/lib/runtime-goal-comparison.js.map +1 -1
- package/src/lib/runtime-html-page.js +3 -2
- package/src/lib/runtime-html-page.js.map +1 -1
- package/src/lib/runtime-layout.js +1 -1
- package/src/lib/runtime-layout.js.map +1 -1
- package/src/lib/runtime-viewer-adapter.d.ts +4 -1
- package/src/lib/runtime-viewer-adapter.js +6 -13
- package/src/lib/runtime-viewer-adapter.js.map +1 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"graph-legend.js","sourceRoot":"","sources":["../../../../../../packages/tooling/nx-webpieces-rules/src/lib/graph-legend.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;GAUG;;;AAEH,oDAAwE;AACxE,2DAoB6B;AAC7B,qDAM0B;AAG1B,4FAA4F;AAC/E,QAAA,eAAe,GAAG,SAAS,CAAC;AACzC,MAAM,QAAQ,GAAG,EAAE,CAAC;AACpB,MAAM,QAAQ,GAAG,EAAE,CAAC;AACpB,MAAM,KAAK,GAAG,SAAS,CAAC;AAExB,MAAa,WAAW;IACpB,+FAA+F;IAC/F,QAAQ,CAAC,KAAkB;QACvB,OAAO,CACH,IAAI,CAAC,OAAO,CAAC,6BAAS,CAAC,OAAO,EAAE,IAAI,CAAC,WAAW,CAAC,KAAK,CAAC,EAAE,KAAK,CAAC;YAC/D,IAAI,CAAC,OAAO,CAAC,6BAAS,CAAC,YAAY,EAAE,IAAI,CAAC,gBAAgB,CAAC,KAAK,CAAC,EAAE,IAAI,CAAC;YACxE,IAAI,CAAC,OAAO,CAAC,6BAAS,CAAC,MAAM,EAAE,IAAI,CAAC,UAAU,EAAE,EAAE,IAAI,CAAC;YACvD,IAAI,CAAC,OAAO,CAAC,6BAAS,CAAC,OAAO,EAAE,IAAI,CAAC,WAAW,CAAC,KAAK,CAAC,EAAE,IAAI,CAAC,CACjE,CAAC;IACN,CAAC;IAED,uFAAuF;IACvF,OAAO;QACH,OAAO,CACH,8BAA8B;YAC9B,IAAI,CAAC,OAAO,CAAC,SAAS,EAAE,EAAE,EAAE,MAAM,EAAE,0CAA0C,CAAC;YAC/E,IAAI,CAAC,OAAO,CAAC,SAAS,EAAE,KAAK,EAAE,YAAY,EAAE,6CAA6C,CAAC;YAC3F,IAAI,CAAC,OAAO,CAAC,SAAS,EAAE,KAAK,EAAE,mBAAmB,EAAE,wCAAwC,CAAC;YAC7F,QAAQ,CACX,CAAC;IACN,CAAC;IAEO,OAAO,CAAC,IAAe,EAAE,IAAY,EAAE,MAAe;QAC1D,MAAM,IAAI,GAAG,MAAM,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC;QACrC,OAAO,oDAAoD,IAAI,IAAI,IAAI,IAAI,IAAI,QAAQ,CAAC;IAC5F,CAAC;IAED,kGAAkG;IAClG,WAAW,CAAC,KAAkB;QAC1B,MAAM,OAAO,GAAG,CAAC,SAAyB,EAAW,EAAE,CAAC,KAAK,CAAC,UAAU,CAAC,QAAQ,CAAC,SAAS,CAAC,CAAC;QAC7F,MAAM,OAAO,GAAqB;YAC9B,GAAG,8BAAU,CAAC,GAAG,CAAC,CAAC,IAAoB,EAAkB,EAAE,CAAC,oCAAgB,CAAC,IAAI,CAAC,CAAC;YACnF,GAAG,4BAAgB,CAAC,GAAG,CAAC,CAAC,CAAiB,EAAkB,EAAE,CAAC,oCAAgB,CAAC,CAAC,CAAC,CAAC,CAAC,MAAM,CACtF,CAAC,KAAqB,EAAW,EAAE,CAAC,CAAC,KAAK,CAAC,MAAM,EAAE,CACtD;SACJ,CAAC;QACF,IAAI,IAAI,GAAG,EAAE,CAAC;QACd,KAAK,MAAM,KAAK,IAAI,OAAO,EAAE,CAAC;YAC1B,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,SAAS,CAAC;gBAAE,SAAS;YACxC,IAAI,IAAI,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,SAAS,EAAE,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,EAAE,KAAK,CAAC,SAAS,EAAE,KAAK,CAAC,WAAW,CAAC,CAAC;QACjG,CAAC;QACD,IAAI,KAAK,CAAC,YAAY;YAClB,IAAI,IAAI,IAAI,CAAC,GAAG,CAAC,OAAO,EAAE,IAAI,CAAC,aAAa,EAAE,EAAE,kBAAkB,EAAE,8BAA8B,CAAC,CAAC;QACxG,IAAI,KAAK,CAAC,SAAS;YACf,IAAI,IAAI,IAAI,CAAC,GAAG,CAAC,MAAM,EAAE,IAAI,CAAC,KAAK,CAAC,oCAAgB,EAAE,EAAE,EAAE,EAAE,CAAC,EAAE,kBAAkB,EAAE,uBAAuB,CAAC,CAAC;QAChH,OAAO,IAAI,CAAC;IAChB,CAAC;IAED,gBAAgB,CAAC,KAAkB;QAC/B,IAAI,IAAI,GAAG,EAAE,CAAC;QACd,KAAK,MAAM,KAAK,IAAI,+BAAW,EAAE,CAAC;YAC9B,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,QAAQ,CAAC,KAAK,CAAC,IAAI,CAAC;gBAAE,SAAS;YAChD,IAAI,IAAI,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,EAAE,IAAI,CAAC,UAAU,CAAC,KAAK,CAAC,EAAE,KAAK,CAAC,IAAI,EAAE,KAAK,CAAC,WAAW,CAAC,CAAC;QACxF,CAAC;QACD,OAAO,IAAI,CAAC;IAChB,CAAC;IAED;;;;OAIG;IACH,UAAU;QACN,OAAO,CACH,IAAI,CAAC,GAAG,CAAC,SAAS,EAAE,IAAI,CAAC,KAAK,CAAC,kCAAc,EAAE,EAAE,EAAE,EAAE,CAAC,EAAE,SAAS,EAAE,qBAAqB,CAAC;YACzF,IAAI,CAAC,GAAG,CACJ,WAAW,EACX,IAAI,CAAC,KAAK,CAAC,oCAAgB,EAAE,kCAAc,EAAE,EAAE,CAAC,EAChD,WAAW,EACX,4EAA4E,CAC/E;YACD,IAAI,CAAC,GAAG,CACJ,UAAU,EACV,IAAI,CAAC,WAAW,EAAE,EAClB,oBAAoB,EACpB,4FAA4F,CAC/F;YACD,IAAI,CAAC,GAAG,CACJ,UAAU,EACV,IAAI,CAAC,KAAK,CAAC,oCAAgB,EAAE,2CAAuB,EAAE,EAAE,CAAC,EACzD,mBAAmB,EACnB,0EAA0E,CAC7E;YACD,IAAI,CAAC,GAAG,CACJ,aAAa,EACb,IAAI,CAAC,KAAK,CAAC,oCAAgB,EAAE,6CAAyB,EAAE,KAAK,CAAC,EAC9D,aAAa,EACb,mDAAmD,CACtD;YACD,IAAI,CAAC,GAAG,CACJ,aAAa,EACb,IAAI,CAAC,KAAK,CAAC,sCAAkB,EAAE,6CAAyB,EAAE,KAAK,CAAC,EAChE,+BAA+B,EAC/B,gDAAgD,CACnD;YACD,IAAI,CAAC,GAAG,CAAC,WAAW,EAAE,IAAI,CAAC,KAAK,CAAC,oCAAgB,EAAE,EAAE,EAAE,EAAE,CAAC,EAAE,mBAAmB,EAAE,6CAA6C,CAAC;YAC/H,IAAI,CAAC,GAAG,CAAC,aAAa,EAAE,IAAI,CAAC,IAAI,CAAC,uBAAe,EAAE,EAAE,CAAC,EAAE,aAAa,EAAE,mDAAmD,CAAC;YAC3H,IAAI,CAAC,GAAG,CAAC,WAAW,EAAE,IAAI,CAAC,IAAI,CAAC,uBAAe,EAAE,KAAK,CAAC,EAAE,WAAW,EAAE,8DAA8D,CAAC;YACrI,IAAI,CAAC,GAAG,CAAC,WAAW,EAAE,IAAI,CAAC,SAAS,EAAE,EAAE,wBAAwB,EAAE,8CAA8C,CAAC;YACjH,oDAAoD,CACvD,CAAC;IACN,CAAC;IAED;;;OAGG;IACH,WAAW,CAAC,KAAkB;QAC1B,IAAI,KAAK,CAAC,QAAQ,CAAC,MAAM,KAAK,CAAC;YAC3B,OAAO,IAAI,CAAC,GAAG,CACX,aAAa,EACb,IAAI,CAAC,KAAK,CAAC,kCAAiB,EAAE,oCAAmB,EAAE,KAAK,CAAC,EACzD,sBAAsB,EACtB,qDAAqD,CACxD,CAAC;QACN,MAAM,OAAO,GAAG,KAAK,CAAC,OAAO,CAAC;QAC9B,IAAI,IAAI,GAAG,EAAE,CAAC;QACd,KAAK,MAAM,KAAK,IAAI,KAAK,CAAC,QAAQ,EAAE,CAAC;YACjC,MAAM,KAAK,GAAG,OAAO,CAAC,OAAO,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;YAC7C,MAAM,MAAM,GAAG,GAAG,KAAK,CAAC,IAAI,SAAS,KAAK,CAAC,OAAO,EAAE,CAAC;YACrD,IAAI,IAAI,IAAI,CAAC,GAAG,CAAC,WAAW,KAAK,CAAC,OAAO,EAAE,EAAE,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,KAAK,EAAE,EAAE,EAAE,EAAE,CAAC,EAAE,GAAG,KAAK,CAAC,OAAO,MAAM,KAAK,CAAC,KAAK,EAAE,EAAE,MAAM,CAAC,CAAC;QAC/H,CAAC;QACD,IAAI,KAAK,CAAC,WAAW,GAAG,CAAC;YACrB,IAAI,IAAI,IAAI,CAAC,GAAG,CACZ,QAAQ,EACR,IAAI,CAAC,KAAK,CAAC,oCAAmB,EAAE,EAAE,EAAE,EAAE,CAAC,EACvC,6BAA6B,KAAK,CAAC,WAAW,EAAE,EAChD,4CAA4C,CAC/C,CAAC;QACN,IAAI,KAAK,CAAC,YAAY;YAClB,IAAI,IAAI,IAAI,CAAC,GAAG,CAAC,SAAS,EAAE,IAAI,CAAC,cAAc,CAAC,OAAO,CAAC,EAAE,kBAAkB,EAAE,wBAAwB,CAAC,CAAC;QAC5G,IAAI,KAAK,CAAC,SAAS,GAAG,CAAC;YACnB,IAAI,IAAI,IAAI,CAAC,GAAG,CACZ,YAAY,EACZ,IAAI,CAAC,KAAK,CAAC,kCAAiB,EAAE,oCAAmB,EAAE,KAAK,CAAC,EACzD,gBAAgB,KAAK,CAAC,SAAS,EAAE,EACjC,4BAA4B,CAC/B,CAAC;QACN,OAAO,IAAI,GAAG,IAAI,CAAC,YAAY,CAAC,KAAK,EAAE,OAAO,CAAC,CAAC;IACpD,CAAC;IAED;;;OAGG;IACH,YAAY,CAAC,KAAkB,EAAE,OAAuB;QACpD,IAAI,IAAI,GAAG,EAAE,CAAC;QACd,IAAI,KAAK,CAAC,iBAAiB,GAAG,CAAC;YAC3B,IAAI,IAAI,IAAI,CAAC,GAAG,CACZ,eAAe,EACf,IAAI,CAAC,IAAI,CAAC,oCAAmB,EAAE,KAAK,CAAC,EACrC,kCAAkC,KAAK,CAAC,iBAAiB,EAAE,EAC3D,mDAAmD,CACtD,CAAC;QACN,MAAM,MAAM,GAAG,KAAK,CAAC,mBAAmB,CAAC;QACzC,IAAI,MAAM,KAAK,IAAI;YAAE,OAAO,IAAI,CAAC;QACjC,MAAM,MAAM,GAAG,MAAM,CAAC,MAAM,CAAC,CAAC,KAA6B,EAAW,EAAE,CAAC,KAAK,CAAC,iBAAiB,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;QAC7G,IAAI,MAAM,CAAC,MAAM,KAAK,CAAC;YACnB,OAAO,CACH,IAAI;gBACJ,IAAI,CAAC,GAAG,CACJ,cAAc,EACd,IAAI,CAAC,IAAI,CAAC,oCAAmB,EAAE,EAAE,CAAC,EAClC,kCAAkC,EAClC,qDAAqD,CACxD,CACJ,CAAC;QACN,KAAK,MAAM,KAAK,IAAI,CAAC,GAAG,MAAM,CAAC,CAAC,IAAI,CAAC,CAAC,CAAyB,EAAE,CAAyB,EAAU,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,aAAa,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC;YAChI,IAAI,IAAI,IAAI,CAAC,GAAG,CACZ,WAAW,KAAK,CAAC,IAAI,EAAE,EACvB,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,EAChD,GAAG,KAAK,CAAC,IAAI,MAAM,CAAC,GAAG,KAAK,CAAC,iBAAiB,CAAC,CAAC,IAAI,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,EACnE,6CAA6C,CAChD,CAAC;QACN,OAAO,IAAI,CAAC;IAChB,CAAC;IAEO,GAAG,CAAC,GAAW,EAAE,MAAc,EAAE,KAAa,EAAE,MAAc;QAClE,OAAO,CACH,8CAA8C,GAAG,KAAK,MAAM,EAAE;YAC9D,SAAS,KAAK,UAAU,MAAM,uBAAuB,CACxD,CAAC;IACN,CAAC;IAEO,IAAI;QACR,OAAO,eAAe,QAAQ,aAAa,QAAQ,kBAAkB,QAAQ,IAAI,QAAQ,uBAAuB,CAAC;IACrH,CAAC;IAEO,KAAK;QACT,OAAO,gCAAgC,QAAQ,GAAG,CAAC,aAAa,QAAQ,GAAG,CAAC,yBAAyB,KAAK,WAAW,CAAC;IAC1H,CAAC;IAED,gFAAgF;IACxE,SAAS,CAAC,KAAqB;QACnC,MAAM,IAAI,GAAG,gBAAgB,QAAQ,aAAa,QAAQ,WAAW,oCAAgB,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,KAAK,KAAK,CAAC;QAC7G,IAAI,KAAK,CAAC,MAAM,EAAE;YAAE,OAAO,IAAI,CAAC,IAAI,EAAE,GAAG,IAAI,GAAG,IAAI,CAAC,KAAK,EAAE,CAAC;QAC7D,MAAM,KAAK,GAAG,4BAA4B,QAAQ,GAAG,CAAC,aAAa,QAAQ,GAAG,CAAC,kBAAkB,KAAK,CAAC,KAAK,KAAK,CAAC;QAClH,OAAO,IAAI,CAAC,IAAI,EAAE,GAAG,IAAI,GAAG,KAAK,GAAG,IAAI,CAAC,KAAK,EAAE,CAAC;IACrD,CAAC;IAED,0EAA0E;IAClE,SAAS;QACb,OAAO,CACH,IAAI,CAAC,IAAI,EAAE;YACX,gBAAgB,QAAQ,aAAa,QAAQ,WAAW,oCAAgB,KAAK;YAC7E,eAAe,QAAQ,GAAG,CAAC,wBAAwB,uBAAe,KAAK;YACvE,YAAY,QAAQ,GAAG,CAAC,qEAAqE;YAC7F,IAAI,CAAC,KAAK,EAAE,CACf,CAAC;IACN,CAAC;IAED,0FAA0F;IAClF,WAAW;QACf,MAAM,KAAK,GAAG,CAAC,CAAC;QAChB,MAAM,KAAK,GAAG,QAAQ,GAAG,KAAK,CAAC;QAC/B,IAAI,OAAO,GAAG,EAAE,CAAC;QACjB,KAAK,IAAI,KAAK,GAAG,CAAC,EAAE,KAAK,GAAG,KAAK,EAAE,KAAK,EAAE;YACtC,OAAO,IAAI,YAAY,CAAC,KAAK,GAAG,KAAK,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,YAAY,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,aAAa,QAAQ,WAAW,KAAK,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,mCAAe,CAAC,CAAC,CAAC,uCAAmB,KAAK,CAAC;QAC9K,MAAM,IAAI,GAAG,4BAA4B,QAAQ,GAAG,CAAC,aAAa,QAAQ,GAAG,CAAC,yBAAyB,0CAAsB,sBAAsB,CAAC;QACpJ,OAAO,IAAI,CAAC,IAAI,EAAE,GAAG,OAAO,GAAG,IAAI,GAAG,IAAI,CAAC,KAAK,EAAE,CAAC;IACvD,CAAC;IAEO,aAAa;QACjB,MAAM,KAAK,GAAG,QAAQ,GAAG,8BAAU,CAAC,MAAM,CAAC;QAC3C,MAAM,OAAO,GAAG,8BAAU,CAAC,GAAG,CAC1B,CAAC,IAAoB,EAAE,KAAa,EAAU,EAAE,CAC5C,YAAY,CAAC,KAAK,GAAG,KAAK,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,YAAY,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,aAAa,QAAQ,WAAW,oCAAgB,CAAC,IAAI,CAAC,CAAC,KAAK,KAAK,CAC1I,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;QACX,OAAO,IAAI,CAAC,IAAI,EAAE,GAAG,OAAO,GAAG,IAAI,CAAC,KAAK,EAAE,CAAC;IAChD,CAAC;IAED,gFAAgF;IACxE,cAAc,CAAC,OAAuB;QAC1C,MAAM,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;QAC1C,MAAM,KAAK,GAAG,QAAQ,GAAG,MAAM,CAAC,MAAM,CAAC;QACvC,MAAM,OAAO,GAAG,MAAM;aACjB,GAAG,CACA,CAAC,KAAmB,EAAE,KAAa,EAAU,EAAE,CAC3C,YAAY,CAAC,KAAK,GAAG,KAAK,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,YAAY,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,aAAa,QAAQ,WAAW,KAAK,CAAC,KAAK,KAAK,CACzH;aACA,IAAI,CAAC,EAAE,CAAC,CAAC;QACd,OAAO,IAAI,CAAC,IAAI,EAAE,GAAG,OAAO,GAAG,IAAI,CAAC,KAAK,EAAE,CAAC;IAChD,CAAC;IAEO,UAAU,CAAC,KAAgB;QAC/B,OAAO,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,IAAI,EAAE,EAAE,EAAE,EAAE,CAAC,CAAC;IAC1C,CAAC;IAED,kFAAkF;IAC1E,KAAK,CAAC,IAAY,EAAE,OAAe,EAAE,IAAY;QACrD,MAAM,MAAM,GAAG,IAAI,KAAK,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,sBAAsB,IAAI,GAAG,CAAC;QAChE,MAAM,IAAI,GACN,OAAO,KAAK,EAAE;YACV,CAAC,CAAC,EAAE;YACJ,CAAC,CAAC,4BAA4B,QAAQ,GAAG,CAAC,aAAa,QAAQ,GAAG,CAAC,yBAAyB,OAAO,qBAAqB,MAAM,IAAI,CAAC;QAC3I,OAAO,IAAI,CAAC,IAAI,EAAE,GAAG,gBAAgB,QAAQ,aAAa,QAAQ,WAAW,IAAI,KAAK,GAAG,IAAI,GAAG,IAAI,CAAC,KAAK,EAAE,CAAC;IACjH,CAAC;IAEO,OAAO,CAAC,KAAa,EAAE,IAAY,EAAE,KAAa,EAAE,MAAc;QACtE,OAAO,IAAI,CAAC,GAAG,CAAC,KAAK,EAAE,IAAI,CAAC,IAAI,CAAC,KAAK,EAAE,IAAI,CAAC,EAAE,KAAK,EAAE,MAAM,CAAC,CAAC;IAClE,CAAC;IAED,+DAA+D;IACvD,IAAI,CAAC,KAAa,EAAE,IAAY;QACpC,MAAM,MAAM,GAAG,IAAI,KAAK,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,sBAAsB,IAAI,GAAG,CAAC;QAChE,OAAO,6FAA6F,KAAK,uBAAuB,MAAM,UAAU,CAAC;IACrJ,CAAC;CACJ;AA3QD,kCA2QC","sourcesContent":["/**\n * The architecture graph's legend, generated per color mode FROM THE PROJECTS ACTUALLY DRAWN.\n *\n * The hand-written legend this replaces listed five frameworks when six existed and never mentioned\n * the `app` and `bundle` borders the renderer drew (#1155). Generating the rows from the same tables\n * the renderer colors with (graph-color-modes.ts) means a color in use always has a row, and a color\n * nothing uses never does.\n *\n * Swatches are inline SVG drawn with presentation attributes, never `style=`, so the page carries\n * no inline CSS.\n */\n\nimport { KNOWN_FRAMEWORKS, KnownFramework } from '@webpieces/rules-sdk';\nimport {\n BASE_ORDER,\n FRAMEWORK_STYLES,\n FrameworkStyle,\n GraphMode,\n IMPACT_BUILD_INPUT,\n IMPACT_BUILD_INPUT_BORDER,\n IMPACT_DEPENDENT,\n IMPACT_IMPLICIT,\n IMPACT_IMPLICIT_BORDER,\n IMPACT_IMPLICIT_GAP,\n IMPACT_ROOT_FILE,\n IMPACT_ROOT_FILE_BORDER,\n IMPACT_TOUCHED,\n IMPACT_UNEXPLAINED_BORDER,\n IMPACT_UNTOUCHED,\n LegendFacts,\n NO_RUNTIME_COLOR,\n ROLE_STYLES,\n RoleStyle,\n} from './graph-color-modes';\nimport {\n PRODUCT_NONE_BORDER,\n PRODUCT_NONE_FILL,\n PRODUCT_SHARED_FILL,\n ProductColor,\n ProductPalette,\n} from './graph-products';\nimport type { ProductDependencyEntry } from '../configs/tag-truth-configs';\n\n/** The page's WpEdgeOverlay.RED: a gained or lost edge, and the edge-only badge (#1264). */\nexport const EDGE_CHANGE_RED = '#d32f2f';\nconst SWATCH_W = 26;\nconst SWATCH_H = 16;\nconst FRAME = '#3a3c46';\n\nexport class GraphLegend {\n /** One section per mode; the page shows the section of the current mode and hides the rest. */\n sections(facts: LegendFacts): string {\n return (\n this.section(GraphMode.RUNTIME, this.runtimeRows(facts), false) +\n this.section(GraphMode.ARCHITECTURE, this.architectureRows(facts), true) +\n this.section(GraphMode.IMPACT, this.impactRows(), true) +\n this.section(GraphMode.PRODUCT, this.productRows(facts), true)\n );\n }\n\n /** The edge key: why a line exists. Static — every graph can carry every edge kind. */\n edgeKey(): string {\n return (\n '<div class=\"wp-legend-list\">' +\n this.edgeRow('#e9eaf0', '', 'uses', 'calls the API, or a plain library import') +\n this.edgeRow('#e9eaf0', '4 3', 'implements', 'serves the API (labeled with its contracts)') +\n this.edgeRow('#7aa2ff', '4 3', 'uses + implements', 'implements some contracts, uses others') +\n '</div>'\n );\n }\n\n private section(mode: GraphMode, rows: string, hidden: boolean): string {\n const hide = hidden ? ' hidden' : '';\n return `<div class=\"wp-legend-list\" data-wp-legend-mode=\"${mode}\"${hide}>${rows}</div>`;\n }\n\n /** Base runtimes first (stripe order), then specializations, in the shared vocabulary's order. */\n runtimeRows(facts: LegendFacts): string {\n const present = (framework: KnownFramework): boolean => facts.frameworks.includes(framework);\n const ordered: FrameworkStyle[] = [\n ...BASE_ORDER.map((base: KnownFramework): FrameworkStyle => FRAMEWORK_STYLES[base]),\n ...KNOWN_FRAMEWORKS.map((f: KnownFramework): FrameworkStyle => FRAMEWORK_STYLES[f]).filter(\n (style: FrameworkStyle): boolean => !style.isBase(),\n ),\n ];\n let rows = '';\n for (const style of ordered) {\n if (!present(style.framework)) continue;\n rows += this.row(style.framework, this.envSwatch(style), style.framework, style.description);\n }\n if (facts.multiRuntime)\n rows += this.row('multi', this.stripesSwatch(), 'several runtimes', 'one equal stripe per runtime');\n if (facts.noRuntime)\n rows += this.row('none', this.solid(NO_RUNTIME_COLOR, '', ''), 'no framework tag', 'runs nowhere declared');\n return rows;\n }\n\n architectureRows(facts: LegendFacts): string {\n let rows = '';\n for (const style of ROLE_STYLES) {\n if (!facts.roles.includes(style.role)) continue;\n rows += this.row(style.role, this.roleSwatch(style), style.role, style.description);\n }\n return rows;\n }\n\n /**\n * Which box is which is only known from the branch's sidecar, so every row shows except\n * \"unexplained\", which the page shows only when the active scan has one. Each affected class says\n * WHY nx included it (#1264) — only the dependent row claims \"uses a changed project\".\n */\n impactRows(): string {\n return (\n this.row('touched', this.solid(IMPACT_TOUCHED, '', ''), 'changed', 'owns a changed file') +\n this.row(\n 'dependent',\n this.solid(IMPACT_DEPENDENT, IMPACT_TOUCHED, ''),\n 'dependent',\n 'uses a changed project: its tests and build re-run (click it for the path)',\n ) +\n this.row(\n 'implicit',\n this.hatchSwatch(),\n 'implicitly touched',\n 'a target input glob ({workspaceRoot}/…) matched a changed file; it uses no changed project',\n ) +\n this.row(\n 'rootFile',\n this.solid(IMPACT_ROOT_FILE, IMPACT_ROOT_FILE_BORDER, ''),\n 'root-file touched',\n 'a lockfile, package.json, tsconfig.base.json or nx.json change marked it',\n ) +\n this.row(\n 'unexplained',\n this.solid(IMPACT_DEPENDENT, IMPACT_UNEXPLAINED_BORDER, '3 2'),\n 'unexplained',\n 'nx marked it affected; nothing here could say why',\n ) +\n this.row(\n 'build-input',\n this.solid(IMPACT_BUILD_INPUT, IMPACT_BUILD_INPUT_BORDER, '3 2'),\n 'dependency (built, unchanged)',\n 'compiled or restored from cache for this build',\n ) +\n this.row('untouched', this.solid(IMPACT_UNTOUCHED, '', ''), 'not in this build', 'nothing here changed or depends on a change') +\n this.row('edge-gained', this.line(EDGE_CHANGE_RED, ''), 'gained edge', 'new on this branch: depends on / calls (click it)') +\n this.row('edge-lost', this.line(EDGE_CHANGE_RED, '4 3'), 'lost edge', 'no longer depends on / calls since the fork point (click it)') +\n this.row('edge-only', this.edgeBadge(), 'only its edges changed', 'gained or lost an edge, owns no changed file') +\n '<p class=\"wp-impact-note\" data-wp-impact-note></p>'\n );\n }\n\n /**\n * Product mode (#1179): one row per product with its counts, then the shared, several-products and\n * no-product rows that some drawn box actually uses.\n */\n productRows(facts: LegendFacts): string {\n if (facts.products.length === 0)\n return this.row(\n 'no-products',\n this.solid(PRODUCT_NONE_FILL, PRODUCT_NONE_BORDER, '3 2'),\n 'no products declared',\n 'tag each project product:<name> to see each product',\n );\n const palette = facts.palette;\n let rows = '';\n for (const count of facts.products) {\n const color = palette.colorOf(count.product);\n const detail = `${count.only} only ${count.product}`;\n rows += this.row(`product:${count.product}`, this.solid(color.color, '', ''), `${count.product} · ${count.total}`, detail);\n }\n if (facts.sharedByAll > 0)\n rows += this.row(\n 'shared',\n this.solid(PRODUCT_SHARED_FILL, '', ''),\n `shared by every product · ${facts.sharedByAll}`,\n 'a change here is a change to every product',\n );\n if (facts.multiProduct)\n rows += this.row('several', this.productStripes(palette), 'several products', 'one stripe per product');\n if (facts.noProduct > 0)\n rows += this.row(\n 'no-product',\n this.solid(PRODUCT_NONE_FILL, PRODUCT_NONE_BORDER, '3 2'),\n `no product · ${facts.noProduct}`,\n 'needs a product:<name> tag',\n );\n return rows + this.boundaryRows(facts, palette);\n }\n\n /**\n * #1204: the dashed cross-product edge, and the product dependency matrix that allows each such\n * edge — `example → openapi, platform` — when the `product-tags` rule supplied one.\n */\n boundaryRows(facts: LegendFacts, palette: ProductPalette): string {\n let rows = '';\n if (facts.crossProductEdges > 0)\n rows += this.row(\n 'cross-product',\n this.line(PRODUCT_NONE_BORDER, '4 3'),\n `crosses into another product · ${facts.crossProductEdges}`,\n \"dashed, in the color of the product it depends on\",\n );\n const matrix = facts.productDependencies;\n if (matrix === null) return rows;\n const stated = matrix.filter((entry: ProductDependencyEntry): boolean => entry.allowedToDependOn.length > 0);\n if (stated.length === 0)\n return (\n rows +\n this.row(\n 'allowed-none',\n this.line(PRODUCT_NONE_BORDER, ''),\n 'no product may depend on another',\n 'product-tags.productDependencies allows no crossing',\n )\n );\n for (const entry of [...stated].sort((a: ProductDependencyEntry, b: ProductDependencyEntry): number => a.name.localeCompare(b.name)))\n rows += this.row(\n `allowed:${entry.name}`,\n this.line(palette.colorOf(entry.name).color, ''),\n `${entry.name} → ${[...entry.allowedToDependOn].sort().join(', ')}`,\n 'allowed by product-tags.productDependencies',\n );\n return rows;\n }\n\n private row(key: string, swatch: string, title: string, detail: string): string {\n return (\n `<div class=\"wp-legend-row\" data-wp-legend=\"${key}\">${swatch}` +\n `<span>${title}<small>${detail}</small></span></div>`\n );\n }\n\n private open(): string {\n return `<svg width=\"${SWATCH_W}\" height=\"${SWATCH_H}\" viewBox=\"0 0 ${SWATCH_W} ${SWATCH_H}\" aria-hidden=\"true\">`;\n }\n\n private frame(): string {\n return `<rect x=\"0.5\" y=\"0.5\" width=\"${SWATCH_W - 1}\" height=\"${SWATCH_H - 1}\" fill=\"none\" stroke=\"${FRAME}\"/></svg>`;\n }\n\n /** A base runtime is solid; a specialization is its inset on the base color. */\n private envSwatch(style: FrameworkStyle): string {\n const base = `<rect width=\"${SWATCH_W}\" height=\"${SWATCH_H}\" fill=\"${FRAMEWORK_STYLES[style.base].color}\"/>`;\n if (style.isBase()) return this.open() + base + this.frame();\n const inset = `<rect x=\"4\" y=\"4\" width=\"${SWATCH_W - 8}\" height=\"${SWATCH_H - 8}\" rx=\"2\" fill=\"${style.color}\"/>`;\n return this.open() + base + inset + this.frame();\n }\n\n /** The red ± badge a box whose only change is an edge carries (#1264). */\n private edgeBadge(): string {\n return (\n this.open() +\n `<rect width=\"${SWATCH_W}\" height=\"${SWATCH_H}\" fill=\"${IMPACT_UNTOUCHED}\"/>` +\n `<circle cx=\"${SWATCH_W - 7}\" cy=\"7\" r=\"6\" fill=\"${EDGE_CHANGE_RED}\"/>` +\n `<text x=\"${SWATCH_W - 7}\" y=\"10\" text-anchor=\"middle\" font-size=\"9\" fill=\"#ffffff\">±</text>` +\n this.frame()\n );\n }\n\n /** The implicitly-touched hatch: thin alternating violet stripes inside a violet ring. */\n private hatchSwatch(): string {\n const count = 8;\n const width = SWATCH_W / count;\n let stripes = '';\n for (let index = 0; index < count; index++)\n stripes += `<rect x=\"${(index * width).toFixed(2)}\" width=\"${width.toFixed(2)}\" height=\"${SWATCH_H}\" fill=\"${index % 2 === 0 ? IMPACT_IMPLICIT : IMPACT_IMPLICIT_GAP}\"/>`;\n const ring = `<rect x=\"2\" y=\"2\" width=\"${SWATCH_W - 4}\" height=\"${SWATCH_H - 4}\" fill=\"none\" stroke=\"${IMPACT_IMPLICIT_BORDER}\" stroke-width=\"2\"/>`;\n return this.open() + stripes + ring + this.frame();\n }\n\n private stripesSwatch(): string {\n const width = SWATCH_W / BASE_ORDER.length;\n const stripes = BASE_ORDER.map(\n (base: KnownFramework, index: number): string =>\n `<rect x=\"${(index * width).toFixed(2)}\" width=\"${width.toFixed(2)}\" height=\"${SWATCH_H}\" fill=\"${FRAMEWORK_STYLES[base].color}\"/>`,\n ).join('');\n return this.open() + stripes + this.frame();\n }\n\n /** The first three product colors as stripes: the \"several products\" swatch. */\n private productStripes(palette: ProductPalette): string {\n const colors = palette.colors.slice(0, 3);\n const width = SWATCH_W / colors.length;\n const stripes = colors\n .map(\n (color: ProductColor, index: number): string =>\n `<rect x=\"${(index * width).toFixed(2)}\" width=\"${width.toFixed(2)}\" height=\"${SWATCH_H}\" fill=\"${color.color}\"/>`,\n )\n .join('');\n return this.open() + stripes + this.frame();\n }\n\n private roleSwatch(style: RoleStyle): string {\n return this.solid(style.fill, '', '');\n }\n\n /** A filled swatch, optionally with an inner ring (dashed when `dash` is set). */\n private solid(fill: string, outline: string, dash: string): string {\n const dashed = dash === '' ? '' : ` stroke-dasharray=\"${dash}\"`;\n const ring =\n outline === ''\n ? ''\n : `<rect x=\"2\" y=\"2\" width=\"${SWATCH_W - 4}\" height=\"${SWATCH_H - 4}\" fill=\"none\" stroke=\"${outline}\" stroke-width=\"2\"${dashed}/>`;\n return this.open() + `<rect width=\"${SWATCH_W}\" height=\"${SWATCH_H}\" fill=\"${fill}\"/>` + ring + this.frame();\n }\n\n private edgeRow(color: string, dash: string, title: string, detail: string): string {\n return this.row(title, this.line(color, dash), title, detail);\n }\n\n /** An edge swatch: a short line, dashed when `dash` is set. */\n private line(color: string, dash: string): string {\n const dashed = dash === '' ? '' : ` stroke-dasharray=\"${dash}\"`;\n return `<svg width=\"28\" height=\"10\" aria-hidden=\"true\"><line x1=\"0\" y1=\"5\" x2=\"28\" y2=\"5\" stroke=\"${color}\" stroke-width=\"1.6\"${dashed}/></svg>`;\n }\n}\n"]}
|
|
1
|
+
{"version":3,"file":"graph-legend.js","sourceRoot":"","sources":["../../../../../../packages/tooling/nx-webpieces-rules/src/lib/graph-legend.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * The architecture graph's legend, generated per color mode FROM THE PROJECTS ACTUALLY DRAWN.\n *\n * The hand-written legend this replaces listed five frameworks when six existed and never mentioned\n * the `app` and `bundle` borders the renderer drew (#1155). Generating the rows from the same tables\n * the renderer colors with (graph-color-modes.ts) means a color in use always has a row, and a color\n * nothing uses never does.\n *\n * Swatches are inline SVG drawn with presentation attributes, never `style=`, so the page carries\n * no inline CSS.\n */\n\nimport { KNOWN_FRAMEWORKS, KnownFramework } from '@webpieces/rules-sdk';\nimport {\n BASE_ORDER,\n FRAMEWORK_STYLES,\n FrameworkStyle,\n GraphMode,\n IMPACT_BUILD_INPUT,\n IMPACT_BUILD_INPUT_BORDER,\n IMPACT_DEPENDENT,\n IMPACT_IMPLICIT,\n IMPACT_IMPLICIT_BORDER,\n IMPACT_IMPLICIT_GAP,\n IMPACT_ROOT_FILE,\n IMPACT_ROOT_FILE_BORDER,\n IMPACT_TOUCHED,\n IMPACT_UNEXPLAINED_BORDER,\n IMPACT_UNTOUCHED,\n LegendFacts,\n NO_RUNTIME_COLOR,\n ROLE_STYLES,\n RoleStyle,\n} from './graph-color-modes';\nimport {\n PRODUCT_NONE_BORDER,\n PRODUCT_NONE_FILL,\n PRODUCT_OFF_BORDER,\n PRODUCT_OFF_FILL,\n PRODUCT_SHARED_FILL,\n PRODUCTS_ON_AT_LOAD,\n ProductColor,\n ProductPalette,\n} from './graph-products';\nimport type { ProductDependencyEntry } from '../configs/tag-truth-configs';\n\n/** The page's WpEdgeOverlay.RED: a gained or lost edge, and the edge-only badge (#1264). */\nexport const EDGE_CHANGE_RED = '#d32f2f';\nconst SWATCH_W = 26;\nconst SWATCH_H = 16;\nconst FRAME = '#3a3c46';\n\nexport class GraphLegend {\n /** One section per mode; the page shows the section of the current mode and hides the rest. */\n sections(facts: LegendFacts): string {\n return (\n this.section(GraphMode.RUNTIME, this.runtimeRows(facts), false) +\n this.section(GraphMode.ARCHITECTURE, this.architectureRows(facts), true) +\n this.section(GraphMode.IMPACT, this.impactRows(), true) +\n this.section(GraphMode.PRODUCT, this.productRows(facts), true)\n );\n }\n\n /** The edge key: why a line exists. Static — every graph can carry every edge kind. */\n edgeKey(): string {\n return (\n '<div class=\"wp-legend-list\">' +\n this.edgeRow('#e9eaf0', '', 'uses', 'calls the API, or a plain library import') +\n this.edgeRow('#e9eaf0', '4 3', 'implements', 'serves the API (labeled with its contracts)') +\n this.edgeRow('#7aa2ff', '4 3', 'uses + implements', 'implements some contracts, uses others') +\n '</div>'\n );\n }\n\n private section(mode: GraphMode, rows: string, hidden: boolean): string {\n const hide = hidden ? ' hidden' : '';\n return `<div class=\"wp-legend-list\" data-wp-legend-mode=\"${mode}\"${hide}>${rows}</div>`;\n }\n\n /** Base runtimes first (stripe order), then specializations, in the shared vocabulary's order. */\n runtimeRows(facts: LegendFacts): string {\n const present = (framework: KnownFramework): boolean => facts.frameworks.includes(framework);\n const ordered: FrameworkStyle[] = [\n ...BASE_ORDER.map((base: KnownFramework): FrameworkStyle => FRAMEWORK_STYLES[base]),\n ...KNOWN_FRAMEWORKS.map((f: KnownFramework): FrameworkStyle => FRAMEWORK_STYLES[f]).filter(\n (style: FrameworkStyle): boolean => !style.isBase(),\n ),\n ];\n let rows = '';\n for (const style of ordered) {\n if (!present(style.framework)) continue;\n rows += this.row(style.framework, this.envSwatch(style), style.framework, style.description);\n }\n if (facts.multiRuntime)\n rows += this.row('multi', this.stripesSwatch(), 'several runtimes', 'one equal stripe per runtime');\n if (facts.noRuntime)\n rows += this.row('none', this.solid(NO_RUNTIME_COLOR, '', ''), 'no framework tag', 'runs nowhere declared');\n return rows;\n }\n\n architectureRows(facts: LegendFacts): string {\n let rows = '';\n for (const style of ROLE_STYLES) {\n if (!facts.roles.includes(style.role)) continue;\n rows += this.row(style.role, this.roleSwatch(style), style.role, style.description);\n }\n return rows;\n }\n\n /**\n * Which box is which is only known from the branch's sidecar, so every row shows except\n * \"unexplained\", which the page shows only when the active scan has one. Each affected class says\n * WHY nx included it (#1264) — only the dependent row claims \"uses a changed project\".\n */\n impactRows(): string {\n return (\n this.row('touched', this.solid(IMPACT_TOUCHED, '', ''), 'changed', 'owns a changed file') +\n this.row(\n 'dependent',\n this.solid(IMPACT_DEPENDENT, IMPACT_TOUCHED, ''),\n 'dependent',\n 'uses a changed project: its tests and build re-run (click it for the path)',\n ) +\n this.row(\n 'implicit',\n this.hatchSwatch(),\n 'implicitly touched',\n 'a target input glob ({workspaceRoot}/…) matched a changed file; it uses no changed project',\n ) +\n this.row(\n 'rootFile',\n this.solid(IMPACT_ROOT_FILE, IMPACT_ROOT_FILE_BORDER, ''),\n 'root-file touched',\n 'a lockfile, package.json, tsconfig.base.json or nx.json change marked it',\n ) +\n this.row(\n 'unexplained',\n this.solid(IMPACT_DEPENDENT, IMPACT_UNEXPLAINED_BORDER, '3 2'),\n 'unexplained',\n 'nx marked it affected; nothing here could say why',\n ) +\n this.row(\n 'build-input',\n this.solid(IMPACT_BUILD_INPUT, IMPACT_BUILD_INPUT_BORDER, '3 2'),\n 'dependency (built, unchanged)',\n 'compiled or restored from cache for this build',\n ) +\n this.row('untouched', this.solid(IMPACT_UNTOUCHED, '', ''), 'not in this build', 'nothing here changed or depends on a change') +\n this.row('edge-gained', this.line(EDGE_CHANGE_RED, ''), 'gained edge', 'new on this branch: depends on / calls (click it)') +\n this.row('edge-lost', this.line(EDGE_CHANGE_RED, '4 3'), 'lost edge', 'no longer depends on / calls since the fork point (click it)') +\n this.row('edge-only', this.edgeBadge(), 'only its edges changed', 'gained or lost an edge, owns no changed file') +\n '<p class=\"wp-impact-note\" data-wp-impact-note></p>'\n );\n }\n\n /**\n * Product mode (#1179): one TOGGLE row per product with its counts (#1319), then the shared,\n * several-products, only-OFF and no-product rows that some drawn box can use. The page switches the\n * first two products ON at every load and repaints from the toggles; colors never move.\n */\n productRows(facts: LegendFacts): string {\n if (facts.products.length === 0)\n return this.row(\n 'no-products',\n this.solid(PRODUCT_NONE_FILL, PRODUCT_NONE_BORDER, '3 2'),\n 'no products declared',\n 'tag each project product:<name> to see each product',\n );\n const palette = facts.palette;\n let rows = '';\n for (const count of facts.products) {\n const color = palette.colorOf(count.product);\n const detail = `${count.only} only ${count.product}`;\n rows += this.productToggle(\n `data-wp-legend=\"product:${count.product}\"`,\n count.product,\n this.solid(color.color, '', '') + `<span>${count.product} · ${count.total}<small>${detail}</small></span>`,\n );\n }\n if (facts.sharedByAll > 0)\n rows += this.row(\n 'shared',\n this.solid(PRODUCT_SHARED_FILL, '', ''),\n `shared by every product · ${facts.sharedByAll}`,\n 'neutral only while every product is ON; a change here is a change to every product',\n );\n if (facts.multiProduct || facts.sharedByAll > 0)\n rows += this.row('several', this.productStripes(palette), 'several products ON', 'one stripe per ON product');\n rows += this.row('off', this.solid(PRODUCT_OFF_FILL, PRODUCT_OFF_BORDER, ''), 'only products switched off', 'light grey; still drawn');\n if (facts.noProduct > 0)\n rows += this.row(\n 'no-product',\n this.solid(PRODUCT_NONE_FILL, PRODUCT_NONE_BORDER, '3 2'),\n `no product · ${facts.noProduct}`,\n 'needs a product:<name> tag',\n );\n return rows + this.productNote() + this.boundaryRows(facts, palette);\n }\n\n /**\n * A product's legend row as a toggle (#1319), shared by both viewers: `attrs` are the row's data\n * attributes and `body` its swatch and text. The page sets every checkbox from its ON set.\n */\n productToggle(attrs: string, product: string, body: string): string {\n return (\n `<label class=\"wp-legend-row wp-product-toggle\" ${attrs}>` +\n `<input type=\"checkbox\" data-wp-product-toggle=\"${product}\">${body}</label>`\n );\n }\n\n /** What the toggles do, in both viewers' Product legend (#1319). */\n productNote(): string {\n return (\n `<p class=\"wp-product-note\">Toggle products to color them; the first ${PRODUCTS_ON_AT_LOAD} are ON on every load. ` +\n 'One ON product: its color · several ON: stripes · only OFF products: light grey · ' +\n 'neutral: carries every product while all are ON · white dashed: no product. A color always means the same product.</p>'\n );\n }\n\n /**\n * #1204: the dashed cross-product edge, and the product dependency matrix that allows each such\n * edge — `example → openapi, platform` — when the `product-tags` rule supplied one.\n */\n boundaryRows(facts: LegendFacts, palette: ProductPalette): string {\n let rows = '';\n if (facts.crossProductEdges > 0)\n rows += this.row(\n 'cross-product',\n this.line(PRODUCT_NONE_BORDER, '4 3'),\n `crosses into another product · ${facts.crossProductEdges}`,\n 'dashed, in the color of the product it depends on, while that product is ON',\n );\n const matrix = facts.productDependencies;\n if (matrix === null) return rows;\n const stated = matrix.filter((entry: ProductDependencyEntry): boolean => entry.allowedToDependOn.length > 0);\n if (stated.length === 0)\n return (\n rows +\n this.row(\n 'allowed-none',\n this.line(PRODUCT_NONE_BORDER, ''),\n 'no product may depend on another',\n 'product-tags.productDependencies allows no crossing',\n )\n );\n for (const entry of [...stated].sort((a: ProductDependencyEntry, b: ProductDependencyEntry): number => a.name.localeCompare(b.name)))\n rows += this.row(\n `allowed:${entry.name}`,\n this.line(palette.colorOf(entry.name).color, ''),\n `${entry.name} → ${[...entry.allowedToDependOn].sort().join(', ')}`,\n 'allowed by product-tags.productDependencies',\n );\n return rows;\n }\n\n private row(key: string, swatch: string, title: string, detail: string): string {\n return (\n `<div class=\"wp-legend-row\" data-wp-legend=\"${key}\">${swatch}` +\n `<span>${title}<small>${detail}</small></span></div>`\n );\n }\n\n private open(): string {\n return `<svg width=\"${SWATCH_W}\" height=\"${SWATCH_H}\" viewBox=\"0 0 ${SWATCH_W} ${SWATCH_H}\" aria-hidden=\"true\">`;\n }\n\n private frame(): string {\n return `<rect x=\"0.5\" y=\"0.5\" width=\"${SWATCH_W - 1}\" height=\"${SWATCH_H - 1}\" fill=\"none\" stroke=\"${FRAME}\"/></svg>`;\n }\n\n /** A base runtime is solid; a specialization is its inset on the base color. */\n private envSwatch(style: FrameworkStyle): string {\n const base = `<rect width=\"${SWATCH_W}\" height=\"${SWATCH_H}\" fill=\"${FRAMEWORK_STYLES[style.base].color}\"/>`;\n if (style.isBase()) return this.open() + base + this.frame();\n const inset = `<rect x=\"4\" y=\"4\" width=\"${SWATCH_W - 8}\" height=\"${SWATCH_H - 8}\" rx=\"2\" fill=\"${style.color}\"/>`;\n return this.open() + base + inset + this.frame();\n }\n\n /** The red ± badge a box whose only change is an edge carries (#1264). */\n private edgeBadge(): string {\n return (\n this.open() +\n `<rect width=\"${SWATCH_W}\" height=\"${SWATCH_H}\" fill=\"${IMPACT_UNTOUCHED}\"/>` +\n `<circle cx=\"${SWATCH_W - 7}\" cy=\"7\" r=\"6\" fill=\"${EDGE_CHANGE_RED}\"/>` +\n `<text x=\"${SWATCH_W - 7}\" y=\"10\" text-anchor=\"middle\" font-size=\"9\" fill=\"#ffffff\">±</text>` +\n this.frame()\n );\n }\n\n /** The implicitly-touched hatch: thin alternating violet stripes inside a violet ring. */\n private hatchSwatch(): string {\n const count = 8;\n const width = SWATCH_W / count;\n let stripes = '';\n for (let index = 0; index < count; index++)\n stripes += `<rect x=\"${(index * width).toFixed(2)}\" width=\"${width.toFixed(2)}\" height=\"${SWATCH_H}\" fill=\"${index % 2 === 0 ? IMPACT_IMPLICIT : IMPACT_IMPLICIT_GAP}\"/>`;\n const ring = `<rect x=\"2\" y=\"2\" width=\"${SWATCH_W - 4}\" height=\"${SWATCH_H - 4}\" fill=\"none\" stroke=\"${IMPACT_IMPLICIT_BORDER}\" stroke-width=\"2\"/>`;\n return this.open() + stripes + ring + this.frame();\n }\n\n private stripesSwatch(): string {\n const width = SWATCH_W / BASE_ORDER.length;\n const stripes = BASE_ORDER.map(\n (base: KnownFramework, index: number): string =>\n `<rect x=\"${(index * width).toFixed(2)}\" width=\"${width.toFixed(2)}\" height=\"${SWATCH_H}\" fill=\"${FRAMEWORK_STYLES[base].color}\"/>`,\n ).join('');\n return this.open() + stripes + this.frame();\n }\n\n /** The first three product colors as stripes: the \"several products ON\" swatch. */\n private productStripes(palette: ProductPalette): string {\n const colors = palette.colors.slice(0, 3);\n const width = SWATCH_W / colors.length;\n const stripes = colors\n .map(\n (color: ProductColor, index: number): string =>\n `<rect x=\"${(index * width).toFixed(2)}\" width=\"${width.toFixed(2)}\" height=\"${SWATCH_H}\" fill=\"${color.color}\"/>`,\n )\n .join('');\n return this.open() + stripes + this.frame();\n }\n\n private roleSwatch(style: RoleStyle): string {\n return this.solid(style.fill, '', '');\n }\n\n /** A filled swatch, optionally with an inner ring (dashed when `dash` is set). */\n private solid(fill: string, outline: string, dash: string): string {\n const dashed = dash === '' ? '' : ` stroke-dasharray=\"${dash}\"`;\n const ring =\n outline === ''\n ? ''\n : `<rect x=\"2\" y=\"2\" width=\"${SWATCH_W - 4}\" height=\"${SWATCH_H - 4}\" fill=\"none\" stroke=\"${outline}\" stroke-width=\"2\"${dashed}/>`;\n return this.open() + `<rect width=\"${SWATCH_W}\" height=\"${SWATCH_H}\" fill=\"${fill}\"/>` + ring + this.frame();\n }\n\n private edgeRow(color: string, dash: string, title: string, detail: string): string {\n return this.row(title, this.line(color, dash), title, detail);\n }\n\n /** An edge swatch: a short line, dashed when `dash` is set. */\n private line(color: string, dash: string): string {\n const dashed = dash === '' ? '' : ` stroke-dasharray=\"${dash}\"`;\n return `<svg width=\"28\" height=\"10\" aria-hidden=\"true\"><line x1=\"0\" y1=\"5\" x2=\"28\" y2=\"5\" stroke=\"${color}\" stroke-width=\"1.6\"${dashed}/></svg>`;\n }\n}\n"]}
|
|
@@ -83,7 +83,7 @@ declare class WpOverlayEdge implements RenderEdgeJson {
|
|
|
83
83
|
readonly from: string;
|
|
84
84
|
readonly to: string;
|
|
85
85
|
readonly dot: string;
|
|
86
|
-
readonly
|
|
86
|
+
readonly crossesInto: string[];
|
|
87
87
|
constructor(id: string, from: string, to: string, dot: string);
|
|
88
88
|
}
|
|
89
89
|
/** The page's own model with the overlay's edges: same boxes, levels and frame. */
|
|
@@ -96,6 +96,7 @@ declare class WpOverlayModel implements RenderModelJson {
|
|
|
96
96
|
readonly header: string;
|
|
97
97
|
readonly footer: string;
|
|
98
98
|
readonly comparison: RuntimeComparisonJson | null;
|
|
99
|
+
readonly legend: LegendJson;
|
|
99
100
|
constructor(base: RenderModelJson, edges: RenderEdgeJson[]);
|
|
100
101
|
}
|
|
101
102
|
/**
|
|
@@ -327,7 +327,7 @@ class WpOverlayEdge {
|
|
|
327
327
|
from;
|
|
328
328
|
to;
|
|
329
329
|
dot;
|
|
330
|
-
|
|
330
|
+
crossesInto = [];
|
|
331
331
|
constructor(id, from, to, dot) {
|
|
332
332
|
this.id = id;
|
|
333
333
|
this.from = from;
|
|
@@ -345,8 +345,10 @@ class WpOverlayModel {
|
|
|
345
345
|
header;
|
|
346
346
|
footer;
|
|
347
347
|
comparison;
|
|
348
|
+
legend;
|
|
348
349
|
constructor(base, edges) {
|
|
349
350
|
this.edges = edges;
|
|
351
|
+
this.legend = base.legend;
|
|
350
352
|
this.viewer = base.viewer;
|
|
351
353
|
this.nodes = base.nodes;
|
|
352
354
|
this.bands = base.bands;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"graph-mode-state.client.js","sourceRoot":"","sources":["../../../../../../packages/tooling/nx-webpieces-rules/src/lib/graph-mode-state.client.ts"],"names":[],"mappings":"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","sourcesContent":["class WpModeState {\n /** `goal` (Goal vs Current, #1239) exists on runtime pages only; the shell renders it nowhere else. */\n static readonly MODES = ['runtime', 'architecture', 'impact', 'product', 'goal'];\n static readonly NAMES = ['Runtime', 'Architecture', 'Impact', 'Product', 'Goal vs Current'];\n static readonly SUBTITLES = [\n 'where the code can run',\n 'servers · clients · APIs',\n 'what changed',\n 'which products it belongs to',\n 'Current → Goal proposal',\n ];\n readonly scans: ImpactJson[] = window.__WP_IMPACT__?.scans ?? [];\n kind = '';\n mode = 'runtime';\n\n /**\n * @param hasProducts some box belongs to a product, so the Product mode has something to show\n * @param goalUnavailable '' when Goal vs Current can be shown, else why not (#1239)\n */\n constructor(\n private readonly hasProducts: boolean,\n private readonly viewer: string,\n private readonly goalUnavailable: string,\n ) {\n this.kind = this.initialKind();\n this.mode = this.initial();\n }\n\n private storageKey(kind: string): string {\n return `wp-${this.viewer}-graph-${kind}`;\n }\n\n /** '' when Product can be shown, else why not. */\n productReason(): string {\n return this.hasProducts\n ? ''\n : 'No products here: tag each project product:<name> in its project.json, then regenerate.';\n }\n\n /** '' when Goal vs Current can be shown, else why not (a missing or unusable input, never \"no differences\"). */\n goalReason(): string {\n return this.goalUnavailable;\n }\n\n /** The active scan; null when the page has no Impact data. */\n get impact(): ImpactJson | null {\n return this.scans.find((scan: ImpactJson): boolean => scan.kind === this.kind) ?? null;\n }\n\n /** '' when Impact can be shown, else the one line the drawer and the Filter popover say instead. */\n impactReason(): string {\n const impact = this.impact;\n if (\n impact === null &&\n this.viewer === 'runtime' &&\n document.body.dataset['wpProjectFacts'] === 'false'\n )\n return 'No saved project facts for Impact. Run pnpm nx run architecture:generate, then pnpm arch:visualize-runtime.';\n if (impact === null)\n return `No impact data here. Run pnpm arch:visualize${this.viewer === 'runtime' ? '-runtime' : ''} to compute it — no full regenerate needed.`;\n return impact.available ? '' : `Impact unavailable (${impact.label}): ${impact.reason}.`;\n }\n\n /** Switch the active scan; false (and nothing changes) for a missing or unavailable one. */\n setKind(kind: string): boolean {\n if (!this.kindAvailable(kind)) return false;\n this.kind = kind;\n // eslint-disable-next-line @webpieces/no-unmanaged-exceptions -- storage is a per-viewer convenience; a blocked store must not break the page\n try {\n localStorage.setItem(this.storageKey('impact-kind'), kind);\n // webpieces-disable no-any-unknown -- browsers may throw any value from blocked storage\n } catch (err: unknown) {\n //const error = toError(err);\n void err;\n }\n return true;\n }\n\n kindAvailable(kind: string): boolean {\n return this.scans.some((scan: ImpactJson): boolean => scan.kind === kind && scan.available);\n }\n\n private initialKind(): string {\n const stored = this.read(this.storageKey('impact-kind'));\n if (stored !== null && this.kindAvailable(stored)) return stored;\n const preferred = window.__WP_IMPACT__?.defaultKind ?? '';\n if (this.scans.some((scan: ImpactJson): boolean => scan.kind === preferred))\n return preferred;\n return this.scans[0]?.kind ?? '';\n }\n\n available(mode: string): boolean {\n if (!WpModeState.MODES.includes(mode)) return false;\n if (mode === 'impact') return this.impactReason() === '';\n if (mode === 'product') return this.productReason() === '';\n if (mode === 'goal') return this.goalReason() === '';\n return true;\n }\n\n name(mode: string): string {\n return WpModeState.NAMES[WpModeState.MODES.indexOf(mode)] ?? mode;\n }\n\n subtitle(mode: string): string {\n return WpModeState.SUBTITLES[WpModeState.MODES.indexOf(mode)] ?? '';\n }\n\n /** False (and nothing changes) for an unknown or unavailable mode. */\n set(mode: string): boolean {\n if (!this.available(mode)) return false;\n this.mode = mode;\n // eslint-disable-next-line @webpieces/no-unmanaged-exceptions -- storage is a per-viewer convenience; a blocked store must not break the page\n try {\n localStorage.setItem(this.storageKey('mode'), mode);\n if (location.hash !== `#${mode}`) history.replaceState(null, '', `#${mode}`);\n // webpieces-disable no-any-unknown -- browsers may throw any value from blocked storage\n } catch (err: unknown) {\n //const error = toError(err);\n void err;\n }\n return true;\n }\n\n /** Which impact shade a box gets, from the ACTIVE scan: WHY nx included it (#1264). */\n status(id: string): 'touched' | 'dependent' | 'implicit' | 'rootFile' | 'unexplained' | 'buildInput' | 'untouched' {\n const impact = this.impact;\n if (impact?.touched.includes(id)) return 'touched';\n if (impact?.dependents.includes(id)) return 'dependent';\n if (impact?.implicit.includes(id)) return 'implicit';\n if (impact?.rootFile.includes(id)) return 'rootFile';\n if (impact?.unexplained.includes(id)) return 'unexplained';\n if (impact?.buildInputs.includes(id)) return 'buildInput';\n return 'untouched';\n }\n\n /** Every affected node id of the active scan, whatever its reason. */\n affected(): string[] {\n const impact = this.impact;\n if (impact === null) return [];\n return [...impact.touched, ...impact.dependents, ...impact.implicit, ...impact.rootFile, ...impact.unexplained];\n }\n\n /** The edges gained and lost since the fork point that THIS page draws: build deps or runtime calls. */\n edgeChanges(): EdgeChangeJson[] {\n const edges = window.__WP_IMPACT__?.edges;\n if (edges === undefined) return [];\n return this.viewer === 'runtime' ? edges.runtime : edges.dependency;\n }\n\n /** '' when this page's edge changes were computed (even if none), else why the page shows none. */\n edgeReason(): string {\n const edges = window.__WP_IMPACT__?.edges;\n if (edges === undefined) return 'No edge changes here. Run pnpm arch:visualize to compute them.';\n return this.viewer === 'runtime' ? edges.runtimeReason : edges.dependencyReason;\n }\n\n /** Every box at either end of a changed edge: the Filter's \"Edge changes only\". */\n edgeEnds(): Set<string> {\n const ends = new Set<string>();\n for (const change of this.edgeChanges()) {\n ends.add(change.from);\n ends.add(change.to);\n }\n return ends;\n }\n\n /** \"Edges since abc1234: 1 gained · 1 lost.\" — or why there are none to show. */\n edgeNote(): string {\n const reason = this.edgeReason();\n if (reason !== '') return `${reason}.`;\n const changes = this.edgeChanges();\n const gained = changes.filter((change: EdgeChangeJson): boolean => change.change === 'gained').length;\n return `Edges since ${window.__WP_IMPACT__?.edges.base ?? ''}: ${gained} gained · ${changes.length - gained} lost.`;\n }\n\n /** Why `id` is in the active scan's build; null when it is not affected. */\n reason(id: string): AffectedReasonJson | null {\n return this.impact?.reasons.find((reason: AffectedReasonJson): boolean => reason.project === id) ?? null;\n }\n\n private initial(): string {\n const hashed = location.hash.slice(1);\n if (this.available(hashed)) return hashed;\n const stored = this.read(this.storageKey('mode'));\n if (stored !== null && this.available(stored)) return stored;\n return 'runtime';\n }\n\n private read(key: string): string | null {\n // eslint-disable-next-line @webpieces/no-unmanaged-exceptions -- storage is a per-viewer convenience; a blocked store reads as \"nothing stored\"\n try {\n return localStorage.getItem(key);\n // webpieces-disable no-any-unknown -- browsers may throw any value from blocked storage\n } catch (err: unknown) {\n //const error = toError(err);\n void err;\n return null;\n }\n }\n}\n\n/**\n * What the \"why\" panel says about one affected project (#1264): never a reason the graph cannot show.\n * Pure text, so a spec reads it without a browser; GraphPage puts it in a panel.\n */\nclass WpImpactWhy {\n static readonly TITLES: Record<string, string> = {\n touched: 'Changed',\n dependent: 'Dependent',\n implicit: 'Implicitly touched',\n rootFile: 'Root-file touched',\n unexplained: 'Unexplained',\n };\n\n /**\n * `8 changed · 3 dependents · 22 implicitly touched (runtime-wiring-check inputs) · 47 dependencies`\n * — the same split ImpactCounts (graph-impact.ts) prints on the console.\n */\n counts(impact: ImpactJson): string {\n const parts = [`${impact.touched.length} changed`, `${impact.dependents.length} dependents`];\n if (impact.implicit.length > 0) {\n const targets = [\n ...new Set(\n impact.reasons\n .filter((reason: AffectedReasonJson): boolean => reason.kind === 'implicit' && reason.target !== '')\n .map((reason: AffectedReasonJson): string => reason.target),\n ),\n ].sort();\n parts.push(`${impact.implicit.length} implicitly touched${targets.length === 0 ? '' : ` (${targets.join(', ')} inputs)`}`);\n }\n if (impact.rootFile.length > 0) parts.push(`${impact.rootFile.length} root-file touched`);\n if (impact.unexplained.length > 0) parts.push(`${impact.unexplained.length} unexplained`);\n parts.push(`${impact.buildInputs.length} dependencies`);\n return parts.join(' · ');\n }\n\n title(reason: AffectedReasonJson): string {\n return `${WpImpactWhy.TITLES[reason.kind] ?? reason.kind}: ${reason.project}`;\n }\n\n lines(reason: AffectedReasonJson): string[] {\n if (reason.kind === 'touched') {\n const owns = reason.files.length === 1 ? 'this changed file' : `these ${reason.files.length} changed files`;\n return [`It owns ${owns}:`, ...reason.files];\n }\n if (reason.kind === 'dependent')\n return [\n 'It uses a changed or touched project through these dependency edges, so its tests and build re-run:',\n reason.path.join(' -> '),\n ];\n if (reason.kind === 'implicit')\n return [\n reason.target === '' ? reason.detail : `${reason.target} input ${reason.input} matched ${reason.files.join(', ')}`,\n 'nx marks every project whose target input glob matches a changed file. It uses no changed project.',\n ];\n if (reason.kind === 'rootFile')\n return [\n reason.detail,\n ...(reason.path.length > 0 ? [reason.path.join(' -> ')] : []),\n 'nx marked it for a workspace root file; it uses no changed project.',\n ];\n return [reason.detail];\n }\n}\n\n/**\n * The \"why is this in the build?\" panel (#1264): opened from an affected box's menu in Impact mode.\n * Text nodes only, so no project name is parsed as HTML.\n */\nclass ImpactWhyPanel {\n private readonly panel = document.createElement('div');\n private readonly text = new WpImpactWhy();\n private anchor: SVGElement | null = null;\n\n constructor() {\n this.panel.className = 'wp-impact-why';\n this.panel.hidden = true;\n this.panel.setAttribute('role', 'dialog');\n this.panel.setAttribute('aria-label', 'Why this project is in the build');\n document.body.append(this.panel);\n document.addEventListener('keydown', (ev: KeyboardEvent) => {\n if (ev.key !== 'Escape' || this.panel.hidden) return;\n ev.stopPropagation();\n this.close();\n }, true);\n document.addEventListener('click', (ev: MouseEvent) => {\n const target = ev.target;\n if (target instanceof Node && !this.panel.contains(target) && !this.anchor?.contains(target)) this.close();\n });\n }\n\n open(node: SVGGElement, reason: AffectedReasonJson): void {\n this.show(node, this.text.title(reason), this.text.lines(reason));\n }\n\n /** Any heading and lines, anchored under `node` (a box, or a changed edge). */\n show(node: SVGElement, title: string, lines: string[]): void {\n this.anchor = node;\n const heading = document.createElement('strong');\n heading.textContent = title;\n const list = document.createElement('ul');\n for (const line of lines) {\n const item = document.createElement('li');\n item.textContent = line;\n list.append(item);\n }\n const close = document.createElement('button');\n close.type = 'button';\n close.textContent = 'Close';\n close.addEventListener('click', () => this.close());\n this.panel.replaceChildren(heading, list, close);\n this.panel.hidden = false;\n const box = node.getBoundingClientRect();\n this.panel.style.left = `${Math.max(12, Math.min(box.left, innerWidth - this.panel.offsetWidth - 12))}px`;\n this.panel.style.top = `${Math.max(12, Math.min(box.bottom + 6, innerHeight - this.panel.offsetHeight - 12))}px`;\n close.focus({ preventScroll: true });\n }\n\n close(): void {\n if (this.panel.hidden) return;\n this.panel.hidden = true;\n const anchor = this.anchor;\n this.anchor = null;\n if (anchor?.isConnected) anchor.focus({ preventScroll: true });\n }\n}\n\n/** A changed edge the saved page does not draw: added to the Impact overlay. */\nclass WpOverlayEdge implements RenderEdgeJson {\n readonly productDot: string | null = null;\n\n constructor(\n readonly id: string,\n readonly from: string,\n readonly to: string,\n readonly dot: string,\n ) {}\n}\n\n/** The page's own model with the overlay's edges: same boxes, levels and frame. */\nclass WpOverlayModel implements RenderModelJson {\n readonly viewer: 'architecture' | 'runtime';\n readonly nodes: RenderNodeJson[];\n readonly bands: RenderBandJson[];\n readonly fullDot: string;\n readonly header: string;\n readonly footer: string;\n readonly comparison: RuntimeComparisonJson | null;\n\n constructor(\n base: RenderModelJson,\n readonly edges: RenderEdgeJson[],\n ) {\n this.viewer = base.viewer;\n this.nodes = base.nodes;\n this.bands = base.bands;\n this.fullDot = base.fullDot;\n this.header = base.header;\n this.footer = base.footer;\n this.comparison = base.comparison ?? null;\n }\n}\n\n/**\n * The edges this branch gained or lost since its fork point, drawn over the page in Impact mode\n * (#1264). A changed edge the page already draws is restyled; one it does not (the page is the saved\n * snapshot, the diff is against the LIVE graph) is added: a gained edge solid red and bold, a lost one\n * a red dashed ghost. Every changed edge is clickable, and a box whose only change is an edge gets a\n * red badge.\n */\nclass WpEdgeOverlay {\n static readonly RED = '#d32f2f';\n static readonly PREFIX = 'wp-edge-change-';\n /** pair key → that pair's changes; null until first asked. */\n private pairs: Map<string, EdgeChangeJson[]> | null = null;\n /** Rendered edge id → the changes it stands for. */\n private readonly byEdgeId = new Map<string, EdgeChangeJson[]>();\n private overlay: RenderModelJson | null = null;\n\n constructor(private readonly modes: WpModeState) {}\n\n private key(from: string, to: string): string {\n return `${from}\\u0000${to}`;\n }\n\n private grouped(): Map<string, EdgeChangeJson[]> {\n if (this.pairs !== null) return this.pairs;\n this.pairs = new Map<string, EdgeChangeJson[]>();\n for (const change of this.modes.edgeChanges()) {\n const key = this.key(change.from, change.to);\n this.pairs.set(key, [...(this.pairs.get(key) ?? []), change]);\n }\n return this.pairs;\n }\n\n any(): boolean {\n return this.modes.edgeChanges().length > 0;\n }\n\n /** `base` plus a ghost statement for every changed edge it does not draw (both ends must be boxes). */\n model(base: RenderModelJson): RenderModelJson {\n if (this.overlay !== null) return this.overlay;\n const ids = new Set(base.nodes.map((node: RenderNodeJson): string => node.id));\n const drawn = new Set(base.edges.map((edge: RenderEdgeJson): string => this.key(edge.from, edge.to)));\n const extra: RenderEdgeJson[] = [];\n for (const key of this.grouped().keys()) {\n const changes = this.grouped().get(key) as EdgeChangeJson[];\n const from = changes[0].from;\n const to = changes[0].to;\n if (drawn.has(key) || !ids.has(from) || !ids.has(to)) continue;\n const id = `${WpEdgeOverlay.PREFIX}${extra.length}`;\n const dot = ` \"${this.esc(from)}\" -> \"${this.esc(to)}\" [id=\"${id}\", constraint=false${this.attrs(changes)}];\\n`;\n this.byEdgeId.set(id, changes);\n extra.push(new WpOverlayEdge(id, from, to, dot));\n }\n this.overlay = new WpOverlayModel(base, [...base.edges, ...extra]);\n return this.overlay;\n }\n\n /** A drawn edge's statement restyled when it changed; null when it did not. */\n edgeDot(edge: RenderEdgeJson): string | null {\n if (edge.id.startsWith(WpEdgeOverlay.PREFIX)) return edge.dot;\n const changes = this.grouped().get(this.key(edge.from, edge.to));\n if (changes === undefined) return null;\n this.byEdgeId.set(edge.id, changes);\n return `${edge.dot.slice(0, -2)} [${this.attrs(changes).slice(2)}];\\n`;\n }\n\n /** Gained (any API new) is solid, bold red; otherwise a lost edge is a red dashed ghost. */\n private attrs(changes: EdgeChangeJson[]): string {\n const gained = changes.some((change: EdgeChangeJson): boolean => change.change === 'gained');\n const tooltip = this.esc(changes.map((change: EdgeChangeJson): string => change.text).join('; '));\n return `, color=\"${WpEdgeOverlay.RED}\", fontcolor=\"${WpEdgeOverlay.RED}\", penwidth=${gained ? '3' : '2'}, style=\"${gained ? 'bold' : 'dashed'}\", tooltip=\"${tooltip}\"`;\n }\n\n private esc(text: string): string {\n return text.replace(/\\\\/g, '\\\\\\\\').replace(/\"/g, '\\\\\"');\n }\n\n /** The lines for one box's edge changes (\"new on this branch: …\", \"… no longer calls …\"). */\n nodeLines(id: string): string[] {\n return this.modes\n .edgeChanges()\n .filter((change: EdgeChangeJson): boolean => change.from === id || change.to === id)\n .map((change: EdgeChangeJson): string => change.text);\n }\n\n /** Every changed edge clickable; a red badge on each box whose ONLY change is an edge. */\n decorate(svg: SVGSVGElement, panel: ImpactWhyPanel): void {\n for (const id of this.byEdgeId.keys()) {\n const edge = svg.querySelector<SVGGElement>(`g.edge[id=\"${id}\"]`);\n const changes = this.byEdgeId.get(id) as EdgeChangeJson[];\n if (edge === null) continue;\n edge.classList.add('wp-edge-change');\n edge.setAttribute('tabindex', '0');\n edge.setAttribute('role', 'button');\n const title = changes.some((change: EdgeChangeJson): boolean => change.change === 'gained') ? 'Gained edge' : 'Lost edge';\n const show = (ev: Event): void => {\n ev.stopPropagation();\n panel.show(edge, title, changes.map((change: EdgeChangeJson): string => change.text));\n };\n edge.addEventListener('click', show);\n edge.addEventListener('keydown', (ev: KeyboardEvent) => {\n if (ev.key === 'Enter' || ev.key === ' ') show(ev);\n });\n }\n const affected = new Set(this.modes.affected());\n const ends = this.modes.edgeEnds();\n svg.querySelectorAll<SVGGElement>('g.node').forEach((node: SVGGElement) => {\n const id = node.querySelector('title')?.textContent ?? '';\n if (!ends.has(id) || affected.has(id)) return;\n node.append(this.badge(node));\n });\n }\n\n private badge(node: SVGGElement): SVGGElement {\n const ns = 'http://www.w3.org/2000/svg';\n const box = node.getBBox();\n const group = document.createElementNS(ns, 'g');\n group.setAttribute('class', 'wp-edge-badge');\n const circle = document.createElementNS(ns, 'circle');\n circle.setAttribute('cx', String(box.x + box.width - 2));\n circle.setAttribute('cy', String(box.y + 2));\n circle.setAttribute('r', '8');\n circle.setAttribute('fill', WpEdgeOverlay.RED);\n const text = document.createElementNS(ns, 'text');\n text.setAttribute('x', String(box.x + box.width - 2));\n text.setAttribute('y', String(box.y + 6));\n text.setAttribute('text-anchor', 'middle');\n text.setAttribute('font-size', '12');\n text.setAttribute('fill', '#ffffff');\n text.textContent = '±';\n const hint = document.createElementNS(ns, 'title');\n hint.textContent = 'Only its edges changed on this branch';\n group.append(circle, text, hint);\n return group;\n }\n}\n"]}
|
|
1
|
+
{"version":3,"file":"graph-mode-state.client.js","sourceRoot":"","sources":["../../../../../../packages/tooling/nx-webpieces-rules/src/lib/graph-mode-state.client.ts"],"names":[],"mappings":"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","sourcesContent":["class WpModeState {\n /** `goal` (Goal vs Current, #1239) exists on runtime pages only; the shell renders it nowhere else. */\n static readonly MODES = ['runtime', 'architecture', 'impact', 'product', 'goal'];\n static readonly NAMES = ['Runtime', 'Architecture', 'Impact', 'Product', 'Goal vs Current'];\n static readonly SUBTITLES = [\n 'where the code can run',\n 'servers · clients · APIs',\n 'what changed',\n 'which products it belongs to',\n 'Current → Goal proposal',\n ];\n readonly scans: ImpactJson[] = window.__WP_IMPACT__?.scans ?? [];\n kind = '';\n mode = 'runtime';\n\n /**\n * @param hasProducts some box belongs to a product, so the Product mode has something to show\n * @param goalUnavailable '' when Goal vs Current can be shown, else why not (#1239)\n */\n constructor(\n private readonly hasProducts: boolean,\n private readonly viewer: string,\n private readonly goalUnavailable: string,\n ) {\n this.kind = this.initialKind();\n this.mode = this.initial();\n }\n\n private storageKey(kind: string): string {\n return `wp-${this.viewer}-graph-${kind}`;\n }\n\n /** '' when Product can be shown, else why not. */\n productReason(): string {\n return this.hasProducts\n ? ''\n : 'No products here: tag each project product:<name> in its project.json, then regenerate.';\n }\n\n /** '' when Goal vs Current can be shown, else why not (a missing or unusable input, never \"no differences\"). */\n goalReason(): string {\n return this.goalUnavailable;\n }\n\n /** The active scan; null when the page has no Impact data. */\n get impact(): ImpactJson | null {\n return this.scans.find((scan: ImpactJson): boolean => scan.kind === this.kind) ?? null;\n }\n\n /** '' when Impact can be shown, else the one line the drawer and the Filter popover say instead. */\n impactReason(): string {\n const impact = this.impact;\n if (\n impact === null &&\n this.viewer === 'runtime' &&\n document.body.dataset['wpProjectFacts'] === 'false'\n )\n return 'No saved project facts for Impact. Run pnpm nx run architecture:generate, then pnpm arch:visualize-runtime.';\n if (impact === null)\n return `No impact data here. Run pnpm arch:visualize${this.viewer === 'runtime' ? '-runtime' : ''} to compute it — no full regenerate needed.`;\n return impact.available ? '' : `Impact unavailable (${impact.label}): ${impact.reason}.`;\n }\n\n /** Switch the active scan; false (and nothing changes) for a missing or unavailable one. */\n setKind(kind: string): boolean {\n if (!this.kindAvailable(kind)) return false;\n this.kind = kind;\n // eslint-disable-next-line @webpieces/no-unmanaged-exceptions -- storage is a per-viewer convenience; a blocked store must not break the page\n try {\n localStorage.setItem(this.storageKey('impact-kind'), kind);\n // webpieces-disable no-any-unknown -- browsers may throw any value from blocked storage\n } catch (err: unknown) {\n //const error = toError(err);\n void err;\n }\n return true;\n }\n\n kindAvailable(kind: string): boolean {\n return this.scans.some((scan: ImpactJson): boolean => scan.kind === kind && scan.available);\n }\n\n private initialKind(): string {\n const stored = this.read(this.storageKey('impact-kind'));\n if (stored !== null && this.kindAvailable(stored)) return stored;\n const preferred = window.__WP_IMPACT__?.defaultKind ?? '';\n if (this.scans.some((scan: ImpactJson): boolean => scan.kind === preferred))\n return preferred;\n return this.scans[0]?.kind ?? '';\n }\n\n available(mode: string): boolean {\n if (!WpModeState.MODES.includes(mode)) return false;\n if (mode === 'impact') return this.impactReason() === '';\n if (mode === 'product') return this.productReason() === '';\n if (mode === 'goal') return this.goalReason() === '';\n return true;\n }\n\n name(mode: string): string {\n return WpModeState.NAMES[WpModeState.MODES.indexOf(mode)] ?? mode;\n }\n\n subtitle(mode: string): string {\n return WpModeState.SUBTITLES[WpModeState.MODES.indexOf(mode)] ?? '';\n }\n\n /** False (and nothing changes) for an unknown or unavailable mode. */\n set(mode: string): boolean {\n if (!this.available(mode)) return false;\n this.mode = mode;\n // eslint-disable-next-line @webpieces/no-unmanaged-exceptions -- storage is a per-viewer convenience; a blocked store must not break the page\n try {\n localStorage.setItem(this.storageKey('mode'), mode);\n if (location.hash !== `#${mode}`) history.replaceState(null, '', `#${mode}`);\n // webpieces-disable no-any-unknown -- browsers may throw any value from blocked storage\n } catch (err: unknown) {\n //const error = toError(err);\n void err;\n }\n return true;\n }\n\n /** Which impact shade a box gets, from the ACTIVE scan: WHY nx included it (#1264). */\n status(id: string): 'touched' | 'dependent' | 'implicit' | 'rootFile' | 'unexplained' | 'buildInput' | 'untouched' {\n const impact = this.impact;\n if (impact?.touched.includes(id)) return 'touched';\n if (impact?.dependents.includes(id)) return 'dependent';\n if (impact?.implicit.includes(id)) return 'implicit';\n if (impact?.rootFile.includes(id)) return 'rootFile';\n if (impact?.unexplained.includes(id)) return 'unexplained';\n if (impact?.buildInputs.includes(id)) return 'buildInput';\n return 'untouched';\n }\n\n /** Every affected node id of the active scan, whatever its reason. */\n affected(): string[] {\n const impact = this.impact;\n if (impact === null) return [];\n return [...impact.touched, ...impact.dependents, ...impact.implicit, ...impact.rootFile, ...impact.unexplained];\n }\n\n /** The edges gained and lost since the fork point that THIS page draws: build deps or runtime calls. */\n edgeChanges(): EdgeChangeJson[] {\n const edges = window.__WP_IMPACT__?.edges;\n if (edges === undefined) return [];\n return this.viewer === 'runtime' ? edges.runtime : edges.dependency;\n }\n\n /** '' when this page's edge changes were computed (even if none), else why the page shows none. */\n edgeReason(): string {\n const edges = window.__WP_IMPACT__?.edges;\n if (edges === undefined) return 'No edge changes here. Run pnpm arch:visualize to compute them.';\n return this.viewer === 'runtime' ? edges.runtimeReason : edges.dependencyReason;\n }\n\n /** Every box at either end of a changed edge: the Filter's \"Edge changes only\". */\n edgeEnds(): Set<string> {\n const ends = new Set<string>();\n for (const change of this.edgeChanges()) {\n ends.add(change.from);\n ends.add(change.to);\n }\n return ends;\n }\n\n /** \"Edges since abc1234: 1 gained · 1 lost.\" — or why there are none to show. */\n edgeNote(): string {\n const reason = this.edgeReason();\n if (reason !== '') return `${reason}.`;\n const changes = this.edgeChanges();\n const gained = changes.filter((change: EdgeChangeJson): boolean => change.change === 'gained').length;\n return `Edges since ${window.__WP_IMPACT__?.edges.base ?? ''}: ${gained} gained · ${changes.length - gained} lost.`;\n }\n\n /** Why `id` is in the active scan's build; null when it is not affected. */\n reason(id: string): AffectedReasonJson | null {\n return this.impact?.reasons.find((reason: AffectedReasonJson): boolean => reason.project === id) ?? null;\n }\n\n private initial(): string {\n const hashed = location.hash.slice(1);\n if (this.available(hashed)) return hashed;\n const stored = this.read(this.storageKey('mode'));\n if (stored !== null && this.available(stored)) return stored;\n return 'runtime';\n }\n\n private read(key: string): string | null {\n // eslint-disable-next-line @webpieces/no-unmanaged-exceptions -- storage is a per-viewer convenience; a blocked store reads as \"nothing stored\"\n try {\n return localStorage.getItem(key);\n // webpieces-disable no-any-unknown -- browsers may throw any value from blocked storage\n } catch (err: unknown) {\n //const error = toError(err);\n void err;\n return null;\n }\n }\n}\n\n/**\n * What the \"why\" panel says about one affected project (#1264): never a reason the graph cannot show.\n * Pure text, so a spec reads it without a browser; GraphPage puts it in a panel.\n */\nclass WpImpactWhy {\n static readonly TITLES: Record<string, string> = {\n touched: 'Changed',\n dependent: 'Dependent',\n implicit: 'Implicitly touched',\n rootFile: 'Root-file touched',\n unexplained: 'Unexplained',\n };\n\n /**\n * `8 changed · 3 dependents · 22 implicitly touched (runtime-wiring-check inputs) · 47 dependencies`\n * — the same split ImpactCounts (graph-impact.ts) prints on the console.\n */\n counts(impact: ImpactJson): string {\n const parts = [`${impact.touched.length} changed`, `${impact.dependents.length} dependents`];\n if (impact.implicit.length > 0) {\n const targets = [\n ...new Set(\n impact.reasons\n .filter((reason: AffectedReasonJson): boolean => reason.kind === 'implicit' && reason.target !== '')\n .map((reason: AffectedReasonJson): string => reason.target),\n ),\n ].sort();\n parts.push(`${impact.implicit.length} implicitly touched${targets.length === 0 ? '' : ` (${targets.join(', ')} inputs)`}`);\n }\n if (impact.rootFile.length > 0) parts.push(`${impact.rootFile.length} root-file touched`);\n if (impact.unexplained.length > 0) parts.push(`${impact.unexplained.length} unexplained`);\n parts.push(`${impact.buildInputs.length} dependencies`);\n return parts.join(' · ');\n }\n\n title(reason: AffectedReasonJson): string {\n return `${WpImpactWhy.TITLES[reason.kind] ?? reason.kind}: ${reason.project}`;\n }\n\n lines(reason: AffectedReasonJson): string[] {\n if (reason.kind === 'touched') {\n const owns = reason.files.length === 1 ? 'this changed file' : `these ${reason.files.length} changed files`;\n return [`It owns ${owns}:`, ...reason.files];\n }\n if (reason.kind === 'dependent')\n return [\n 'It uses a changed or touched project through these dependency edges, so its tests and build re-run:',\n reason.path.join(' -> '),\n ];\n if (reason.kind === 'implicit')\n return [\n reason.target === '' ? reason.detail : `${reason.target} input ${reason.input} matched ${reason.files.join(', ')}`,\n 'nx marks every project whose target input glob matches a changed file. It uses no changed project.',\n ];\n if (reason.kind === 'rootFile')\n return [\n reason.detail,\n ...(reason.path.length > 0 ? [reason.path.join(' -> ')] : []),\n 'nx marked it for a workspace root file; it uses no changed project.',\n ];\n return [reason.detail];\n }\n}\n\n/**\n * The \"why is this in the build?\" panel (#1264): opened from an affected box's menu in Impact mode.\n * Text nodes only, so no project name is parsed as HTML.\n */\nclass ImpactWhyPanel {\n private readonly panel = document.createElement('div');\n private readonly text = new WpImpactWhy();\n private anchor: SVGElement | null = null;\n\n constructor() {\n this.panel.className = 'wp-impact-why';\n this.panel.hidden = true;\n this.panel.setAttribute('role', 'dialog');\n this.panel.setAttribute('aria-label', 'Why this project is in the build');\n document.body.append(this.panel);\n document.addEventListener('keydown', (ev: KeyboardEvent) => {\n if (ev.key !== 'Escape' || this.panel.hidden) return;\n ev.stopPropagation();\n this.close();\n }, true);\n document.addEventListener('click', (ev: MouseEvent) => {\n const target = ev.target;\n if (target instanceof Node && !this.panel.contains(target) && !this.anchor?.contains(target)) this.close();\n });\n }\n\n open(node: SVGGElement, reason: AffectedReasonJson): void {\n this.show(node, this.text.title(reason), this.text.lines(reason));\n }\n\n /** Any heading and lines, anchored under `node` (a box, or a changed edge). */\n show(node: SVGElement, title: string, lines: string[]): void {\n this.anchor = node;\n const heading = document.createElement('strong');\n heading.textContent = title;\n const list = document.createElement('ul');\n for (const line of lines) {\n const item = document.createElement('li');\n item.textContent = line;\n list.append(item);\n }\n const close = document.createElement('button');\n close.type = 'button';\n close.textContent = 'Close';\n close.addEventListener('click', () => this.close());\n this.panel.replaceChildren(heading, list, close);\n this.panel.hidden = false;\n const box = node.getBoundingClientRect();\n this.panel.style.left = `${Math.max(12, Math.min(box.left, innerWidth - this.panel.offsetWidth - 12))}px`;\n this.panel.style.top = `${Math.max(12, Math.min(box.bottom + 6, innerHeight - this.panel.offsetHeight - 12))}px`;\n close.focus({ preventScroll: true });\n }\n\n close(): void {\n if (this.panel.hidden) return;\n this.panel.hidden = true;\n const anchor = this.anchor;\n this.anchor = null;\n if (anchor?.isConnected) anchor.focus({ preventScroll: true });\n }\n}\n\n/** A changed edge the saved page does not draw: added to the Impact overlay. */\nclass WpOverlayEdge implements RenderEdgeJson {\n readonly crossesInto: string[] = [];\n\n constructor(\n readonly id: string,\n readonly from: string,\n readonly to: string,\n readonly dot: string,\n ) {}\n}\n\n/** The page's own model with the overlay's edges: same boxes, levels and frame. */\nclass WpOverlayModel implements RenderModelJson {\n readonly viewer: 'architecture' | 'runtime';\n readonly nodes: RenderNodeJson[];\n readonly bands: RenderBandJson[];\n readonly fullDot: string;\n readonly header: string;\n readonly footer: string;\n readonly comparison: RuntimeComparisonJson | null;\n readonly legend: LegendJson;\n\n constructor(\n base: RenderModelJson,\n readonly edges: RenderEdgeJson[],\n ) {\n this.legend = base.legend;\n this.viewer = base.viewer;\n this.nodes = base.nodes;\n this.bands = base.bands;\n this.fullDot = base.fullDot;\n this.header = base.header;\n this.footer = base.footer;\n this.comparison = base.comparison ?? null;\n }\n}\n\n/**\n * The edges this branch gained or lost since its fork point, drawn over the page in Impact mode\n * (#1264). A changed edge the page already draws is restyled; one it does not (the page is the saved\n * snapshot, the diff is against the LIVE graph) is added: a gained edge solid red and bold, a lost one\n * a red dashed ghost. Every changed edge is clickable, and a box whose only change is an edge gets a\n * red badge.\n */\nclass WpEdgeOverlay {\n static readonly RED = '#d32f2f';\n static readonly PREFIX = 'wp-edge-change-';\n /** pair key → that pair's changes; null until first asked. */\n private pairs: Map<string, EdgeChangeJson[]> | null = null;\n /** Rendered edge id → the changes it stands for. */\n private readonly byEdgeId = new Map<string, EdgeChangeJson[]>();\n private overlay: RenderModelJson | null = null;\n\n constructor(private readonly modes: WpModeState) {}\n\n private key(from: string, to: string): string {\n return `${from}\\u0000${to}`;\n }\n\n private grouped(): Map<string, EdgeChangeJson[]> {\n if (this.pairs !== null) return this.pairs;\n this.pairs = new Map<string, EdgeChangeJson[]>();\n for (const change of this.modes.edgeChanges()) {\n const key = this.key(change.from, change.to);\n this.pairs.set(key, [...(this.pairs.get(key) ?? []), change]);\n }\n return this.pairs;\n }\n\n any(): boolean {\n return this.modes.edgeChanges().length > 0;\n }\n\n /** `base` plus a ghost statement for every changed edge it does not draw (both ends must be boxes). */\n model(base: RenderModelJson): RenderModelJson {\n if (this.overlay !== null) return this.overlay;\n const ids = new Set(base.nodes.map((node: RenderNodeJson): string => node.id));\n const drawn = new Set(base.edges.map((edge: RenderEdgeJson): string => this.key(edge.from, edge.to)));\n const extra: RenderEdgeJson[] = [];\n for (const key of this.grouped().keys()) {\n const changes = this.grouped().get(key) as EdgeChangeJson[];\n const from = changes[0].from;\n const to = changes[0].to;\n if (drawn.has(key) || !ids.has(from) || !ids.has(to)) continue;\n const id = `${WpEdgeOverlay.PREFIX}${extra.length}`;\n const dot = ` \"${this.esc(from)}\" -> \"${this.esc(to)}\" [id=\"${id}\", constraint=false${this.attrs(changes)}];\\n`;\n this.byEdgeId.set(id, changes);\n extra.push(new WpOverlayEdge(id, from, to, dot));\n }\n this.overlay = new WpOverlayModel(base, [...base.edges, ...extra]);\n return this.overlay;\n }\n\n /** A drawn edge's statement restyled when it changed; null when it did not. */\n edgeDot(edge: RenderEdgeJson): string | null {\n if (edge.id.startsWith(WpEdgeOverlay.PREFIX)) return edge.dot;\n const changes = this.grouped().get(this.key(edge.from, edge.to));\n if (changes === undefined) return null;\n this.byEdgeId.set(edge.id, changes);\n return `${edge.dot.slice(0, -2)} [${this.attrs(changes).slice(2)}];\\n`;\n }\n\n /** Gained (any API new) is solid, bold red; otherwise a lost edge is a red dashed ghost. */\n private attrs(changes: EdgeChangeJson[]): string {\n const gained = changes.some((change: EdgeChangeJson): boolean => change.change === 'gained');\n const tooltip = this.esc(changes.map((change: EdgeChangeJson): string => change.text).join('; '));\n return `, color=\"${WpEdgeOverlay.RED}\", fontcolor=\"${WpEdgeOverlay.RED}\", penwidth=${gained ? '3' : '2'}, style=\"${gained ? 'bold' : 'dashed'}\", tooltip=\"${tooltip}\"`;\n }\n\n private esc(text: string): string {\n return text.replace(/\\\\/g, '\\\\\\\\').replace(/\"/g, '\\\\\"');\n }\n\n /** The lines for one box's edge changes (\"new on this branch: …\", \"… no longer calls …\"). */\n nodeLines(id: string): string[] {\n return this.modes\n .edgeChanges()\n .filter((change: EdgeChangeJson): boolean => change.from === id || change.to === id)\n .map((change: EdgeChangeJson): string => change.text);\n }\n\n /** Every changed edge clickable; a red badge on each box whose ONLY change is an edge. */\n decorate(svg: SVGSVGElement, panel: ImpactWhyPanel): void {\n for (const id of this.byEdgeId.keys()) {\n const edge = svg.querySelector<SVGGElement>(`g.edge[id=\"${id}\"]`);\n const changes = this.byEdgeId.get(id) as EdgeChangeJson[];\n if (edge === null) continue;\n edge.classList.add('wp-edge-change');\n edge.setAttribute('tabindex', '0');\n edge.setAttribute('role', 'button');\n const title = changes.some((change: EdgeChangeJson): boolean => change.change === 'gained') ? 'Gained edge' : 'Lost edge';\n const show = (ev: Event): void => {\n ev.stopPropagation();\n panel.show(edge, title, changes.map((change: EdgeChangeJson): string => change.text));\n };\n edge.addEventListener('click', show);\n edge.addEventListener('keydown', (ev: KeyboardEvent) => {\n if (ev.key === 'Enter' || ev.key === ' ') show(ev);\n });\n }\n const affected = new Set(this.modes.affected());\n const ends = this.modes.edgeEnds();\n svg.querySelectorAll<SVGGElement>('g.node').forEach((node: SVGGElement) => {\n const id = node.querySelector('title')?.textContent ?? '';\n if (!ends.has(id) || affected.has(id)) return;\n node.append(this.badge(node));\n });\n }\n\n private badge(node: SVGGElement): SVGGElement {\n const ns = 'http://www.w3.org/2000/svg';\n const box = node.getBBox();\n const group = document.createElementNS(ns, 'g');\n group.setAttribute('class', 'wp-edge-badge');\n const circle = document.createElementNS(ns, 'circle');\n circle.setAttribute('cx', String(box.x + box.width - 2));\n circle.setAttribute('cy', String(box.y + 2));\n circle.setAttribute('r', '8');\n circle.setAttribute('fill', WpEdgeOverlay.RED);\n const text = document.createElementNS(ns, 'text');\n text.setAttribute('x', String(box.x + box.width - 2));\n text.setAttribute('y', String(box.y + 6));\n text.setAttribute('text-anchor', 'middle');\n text.setAttribute('font-size', '12');\n text.setAttribute('fill', '#ffffff');\n text.textContent = '±';\n const hint = document.createElementNS(ns, 'title');\n hint.textContent = 'Only its edges changed on this branch';\n group.append(circle, text, hint);\n return group;\n }\n}\n"]}
|
|
@@ -235,7 +235,7 @@ class GraphPageShell {
|
|
|
235
235
|
<p>Click a box for Lock, Filter Unconnected, or Implements. Implements in the box is a plain summary. Click Uses on a relationship line for its complete details. Hover traces chains without opening details.</p>
|
|
236
236
|
<p>Lock pins separate incoming and outgoing chains; hover adds another chain temporarily. Hide unconnected removes unrelated boxes independently. Clear all clears facets, leaving Lock and chain filtering intact.</p>
|
|
237
237
|
<p>Filters intersect declared runtime, role, product closure and Nx build scope. Counts describe services; attached contextual nodes are counted separately. Impact uses compile-project sets, never runtime reachability. Queues and vendors are context, never source owners or CI projects.</p>
|
|
238
|
-
<p>Runtime uses declared framework colors, Architecture declared roles; contextual nodes keep their kind colors. Product colors come from each project's declared product: tags; contextual nodes inherit adjacent memberships. Unknown metadata is neutral. Missing saved metadata requires explicit architecture:generate.</p>
|
|
238
|
+
<p>Runtime uses declared framework colors, Architecture declared roles; contextual nodes keep their kind colors. Product colors come from each project's declared product: tags, painted for the products toggled ON in the legend (the first two on every load); contextual nodes inherit adjacent memberships. Unknown metadata is neutral. Missing saved metadata requires explicit architecture:generate.</p>
|
|
239
239
|
<p><strong>Goal vs Current</strong> compares the saved goal (architecture/runtime-dependencies-goal.json) with the saved current graph, Current → Goal: green added, red dashed removed (still drawn), amber changed, grey unchanged. Click a box for its before/after details, or click an arrow.</p>
|
|
240
240
|
<p><kbd>/</kbd> Focus search · <kbd>1</kbd>–<kbd>5</kbd> modes · <kbd>Esc</kbd> dismiss or unlock</p>
|
|
241
241
|
</div>`;
|
|
@@ -245,7 +245,7 @@ class GraphPageShell {
|
|
|
245
245
|
<p>💡 <strong>Click any box</strong> for its menu: <strong>View Design</strong> (only where the project has a generated <strong>design.html</strong>, i.e. what the AI sees inside it), <strong>Lock/Unlock</strong> (the same lock as the Focus field), <strong>Filter Unconnected</strong> (removes unrelated boxes, keeping each L-number row).</p>
|
|
246
246
|
<p><strong>Filter</strong> narrows the graph by what changed on this branch or in the last commit, by runtime, by role and by product; the groups combine. A product keeps its servers, clients and apps plus everything they depend on, so <strong>Product</strong> + <strong>Changed + dependents + dependencies</strong> is exactly what this branch builds that can affect that product. Every box keeps its own L-row, and a level left empty shows as a thin labeled band.</p>
|
|
247
247
|
<p>🔦 <strong>Hover any box</strong> to trace its <em>entire</em> dependency chain — every ancestor above it and every dependency below it, with the lines between — while the rest of the graph dims.</p>
|
|
248
|
-
<p><strong>Runtime</strong>: a box may depend on a box carrying every color it has. <strong>Architecture</strong>: what each box is in the system. <strong>Impact</strong>: what changed on this branch or in the last commit (amber), its dependents (amber outline), and what nx marked for another reason: an input glob (violet hatch) or a root file (teal). Click an affected box for why; with both available, a toggle picks which. <strong>Product</strong>: which products each box belongs to
|
|
248
|
+
<p><strong>Runtime</strong>: a box may depend on a box carrying every color it has. <strong>Architecture</strong>: what each box is in the system. <strong>Impact</strong>: what changed on this branch or in the last commit (amber), its dependents (amber outline), and what nx marked for another reason: an input glob (violet hatch) or a root file (teal). Click an affected box for why; with both available, a toggle picks which. <strong>Product</strong>: which products each box belongs to. Toggle products in the legend (the first two are ON on every load): one ON product is its color, several ON are stripes, only OFF products are light grey, neutral means every product while all are ON, and a dashed white box belongs to none.</p>
|
|
249
249
|
<p><kbd>/</kbd> focus the lock search · <kbd>1</kbd> <kbd>2</kbd> <kbd>3</kbd> <kbd>4</kbd> switch mode · <kbd>Esc</kbd> unlock</p>
|
|
250
250
|
</div>`;
|
|
251
251
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"graph-page-shell.js","sourceRoot":"","sources":["../../../../../../packages/tooling/nx-webpieces-rules/src/lib/graph-page-shell.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * The architecture page's shell (#1155): a collapsible dark drawer on the left holding every control,\n * and the graph filling the rest of the viewport.\n *\n * Before this, two hint paragraphs, a ~650px three-column legend, a lock dropdown and a zoom bar all\n * sat ABOVE the graph, so a laptop's first screen showed no graph at all. Now the hints are a \"?\"\n * popover, the legend lives in the drawer (and can pop out over the graph), zoom floats bottom-right\n * (graph-navigation.ts) and the responsibilities open in a right-hand panel.\n *\n * Markup only. Behaviour is graph-visualizer.client.ts; styling is graph-page-styles.ts. No element\n * carries a `style=` attribute — every look is a class.\n */\n\nimport { FRAMEWORK_ORDER, GRAPH_MODES, GraphMode, ModeInfo, ROLE_STYLES, RoleStyle, RUNTIME_GRAPH_MODES } from './graph-color-modes';\nimport { ProductColor } from './graph-products';\n\n/**\n * The Filter popover's \"Changes on this branch\" choices. The page computes each set from the Impact\n * sidecar (graph-impact.ts): CHANGED = touched; DEPENDENTS = every project nx affected, whatever its reason (their\n * tests re-run); DEPENDENCIES = touched + every transitive dependency of it; BUILD = touched +\n * every affected project + every build input — the dependencies of the DEPENDENTS too, which is why it is more than\n * the union of the two rows above it.\n *\n * \"Dependents\" are what USE a project and \"dependencies\" what it uses (#1179). \"Dependee\" would mean\n * the thing depended ON — the opposite of the dependents row — so it is never used.\n */\nexport enum ChangeScope {\n EVERYTHING = 'everything',\n CHANGED = 'changed',\n DEPENDENTS = 'dependents',\n DEPENDENCIES = 'dependencies',\n BUILD = 'build',\n /** #1264: the boxes at either end of an edge gained or lost since the fork point. */\n EDGES = 'edges',\n}\n\n/**\n * One change scope: its name and the grey second line under it, like the Color-by menu. These are the\n * ONE copy of the labels — the page script reads each name back from its `data-wp-scope-label` (the\n * top-bar pill), so the two cannot drift apart.\n */\nexport class ScopeOption {\n constructor(\n public readonly scope: ChangeScope,\n public readonly label: string,\n public readonly subtitle: string,\n ) {}\n}\n\nexport const SCOPE_OPTIONS: readonly ScopeOption[] = [\n new ScopeOption(ChangeScope.EVERYTHING, 'All', 'every project'),\n new ScopeOption(ChangeScope.CHANGED, 'Changed', 'owns a changed file'),\n new ScopeOption(ChangeScope.DEPENDENTS, 'Changed + dependents', '+ everything else nx affected: dependents, implicitly and root-file touched (their tests re-run)'),\n new ScopeOption(ChangeScope.DEPENDENCIES, 'Changed + dependencies', '+ everything they use'),\n new ScopeOption(ChangeScope.BUILD, 'Changed + dependents + dependencies', 'everything CI builds for this branch'),\n new ScopeOption(ChangeScope.EDGES, 'Edge changes only', 'projects that gained or lost a dependency or call since the fork point'),\n];\n\n/** Everything the shell frames, already rendered by its owner. */\nexport class ShellParts {\n constructor(\n public readonly title: string,\n public readonly lockControl: string,\n public readonly legend: string,\n public readonly edgeKey: string,\n public readonly filterStatus: string,\n public readonly snapshot: string,\n public readonly responsibilities: string,\n /**\n * One chip per product (#1179), sorted, each colored from the page's ONE palette (#1244);\n * empty hides the Filter's Product group.\n */\n public readonly products: ProductColor[],\n public readonly runtime: boolean = false,\n public readonly frameworks: readonly string[] = FRAMEWORK_ORDER,\n public readonly roles: readonly string[] = ROLE_STYLES.map((style: RoleStyle): string => style.role),\n public readonly emptyState: string = '',\n ) {}\n}\n\nexport class GraphPageShell {\n body(parts: ShellParts): string {\n return `<div class=\"wp-shell\" id=\"wp-shell\">\n ${this.drawer(parts)}\n <main class=\"wp-main\">\n ${this.topbar(parts)}\n <div id=\"graph\"></div>\n ${this.overlays(parts)}\n </main>\n</div>`;\n }\n\n private drawer(parts: ShellParts): string {\n return `<aside class=\"wp-side\" id=\"wp-side\" aria-label=\"Graph controls\">\n <div class=\"wp-brand\">${this.brandIcon()}<span>${parts.title}</span></div>\n <div class=\"wp-group\" role=\"group\" aria-label=\"Color mode\">\n <div class=\"wp-label\">Color by</div>\n ${this.modePulldown(parts.runtime ? RUNTIME_GRAPH_MODES : GRAPH_MODES)}\n <p class=\"wp-mode-reason\" id=\"wp-impact-reason\" hidden></p>\n ${this.impactKinds('drawer')}\n </div>\n <div class=\"wp-group\">\n <button type=\"button\" class=\"wp-filter-btn\" id=\"wp-filter-open\" aria-controls=\"wp-filter-pop\" aria-expanded=\"false\"><span>Filter</span><span class=\"wp-badge\" id=\"wp-filter-badge\" hidden>0</span></button>\n </div>\n <div class=\"wp-group\">\n <label class=\"wp-label\" for=\"wp-lock\">Focus</label>\n ${parts.lockControl}\n <button type=\"button\" class=\"wp-toggle\" id=\"wp-lock-toggle\" aria-pressed=\"false\">Lock <span class=\"wp-sw\" aria-hidden=\"true\"></span></button>\n <button type=\"button\" class=\"wp-toggle\" id=\"wp-filter-toggle\" aria-pressed=\"false\">Hide unconnected <span class=\"wp-sw\" aria-hidden=\"true\"></span></button>\n </div>\n <div class=\"wp-group\">\n <div class=\"wp-label wp-label-row\">Legend <button type=\"button\" class=\"wp-icon wp-icon-mini wp-icon-dark\" id=\"wp-legend-pop\" title=\"Pop the legend out over the graph\" aria-label=\"Pop the legend out over the graph\">⇱</button></div>\n ${parts.legend}\n </div>\n <div class=\"wp-group\">\n <div class=\"wp-label\">Edges</div>\n ${parts.edgeKey}\n </div>\n <div class=\"wp-foot\">\n <button type=\"button\" class=\"wp-link\" id=\"wp-resp-open\" aria-expanded=\"false\">Responsibilities</button>\n <button type=\"button\" class=\"wp-link\" id=\"wp-snapshot-open\" aria-expanded=\"false\">Saved snapshot</button>\n </div>\n </aside>`;\n }\n\n /**\n * \"Color by\": ONE pill-shaped trigger showing the current mode (name + subtitle) that opens a\n * menu of the four. Keys 1/2/3/4 and the #runtime / #architecture / #impact / #product links still\n * switch.\n */\n private modePulldown(modes: readonly ModeInfo[]): string {\n const first = modes[0];\n return `<div class=\"wp-pulldown\">\n <button type=\"button\" class=\"wp-pill-trigger\" id=\"wp-mode-trigger\" aria-haspopup=\"menu\" aria-controls=\"wp-mode-menu\" aria-expanded=\"false\">\n <span class=\"wp-pill-text\"><span class=\"wp-mode-name\" id=\"wp-mode-current\">${first.name}</span><span class=\"wp-mode-sub\" id=\"wp-mode-current-sub\">${first.subtitle}</span></span><span class=\"wp-caret\" aria-hidden=\"true\">▾</span>\n </button>\n <div class=\"wp-menu\" id=\"wp-mode-menu\" role=\"menu\" aria-label=\"Color by\" hidden>${modes.map((info: ModeInfo, index: number): string => this.modeItem(info, index)).join('')}</div>\n </div>`;\n }\n\n /** One menu option, two lines: the mode's name, then its grey subtitle. */\n private modeItem(info: ModeInfo, index: number): string {\n const checked = info.mode === GraphMode.RUNTIME ? 'true' : 'false';\n return (\n `<button type=\"button\" class=\"wp-mode\" role=\"menuitemradio\" data-wp-mode=\"${info.mode}\" aria-checked=\"${checked}\" title=\"Key ${index + 1}\">` +\n `<span class=\"wp-mode-name\">${info.name}</span><span class=\"wp-mode-sub\">${info.subtitle}</span></button>`\n );\n }\n\n /**\n * The Filter popover. Its four groups INTERSECT: a box is shown when it is in the chosen change\n * scope AND carries any selected runtime chip (when any is selected) AND any selected role chip\n * (when any is selected) AND belongs to any selected product (when any is selected). Nothing\n * applies until \"Show N projects\".\n */\n private filterPopover(parts: ShellParts): string {\n const scopes = SCOPE_OPTIONS.map(\n (option: ScopeOption): string =>\n `<label class=\"wp-scope\"><input type=\"radio\" name=\"wp-scope\" value=\"${option.scope}\"${option.scope === ChangeScope.EVERYTHING ? ' checked' : ''}>` +\n `<span class=\"wp-scope-text\"><span class=\"wp-scope-name\" data-wp-scope-label=\"${option.scope}\">${option.label}</span>` +\n `<span class=\"wp-scope-sub\">${parts.runtime && option.scope === ChangeScope.EVERYTHING ? 'every service' : option.subtitle}</span></span>` +\n `<span class=\"wp-count\" data-wp-scope-count=\"${option.scope}\"></span></label>`,\n ).join('');\n const chips = (group: string, values: readonly string[]): string =>\n values\n .map(\n (value: string): string =>\n `<button type=\"button\" class=\"wp-chip\" data-wp-chip-group=\"${group}\" data-wp-chip=\"${value}\" aria-pressed=\"false\">${value}</button>`,\n )\n .join('');\n return `<div class=\"wp-pop wp-filter-pop\" id=\"wp-filter-pop\" role=\"dialog\" aria-label=\"Filter ${parts.runtime ? 'services' : 'projects'}\" hidden>\n <header><span>Filter</span><button type=\"button\" class=\"wp-icon wp-icon-mini\" id=\"wp-filter-close\" aria-label=\"Close the filter\">✕</button></header>\n <fieldset class=\"wp-fgroup\" id=\"wp-scope-group\"><legend id=\"wp-scope-legend\">Changes on this branch</legend>${this.impactKinds('filter')}${scopes}<p class=\"wp-scope-reason\" id=\"wp-scope-reason\" hidden></p></fieldset>\n <fieldset class=\"wp-fgroup\"><legend>Runtime <small>any match</small></legend><div class=\"wp-chips\">${chips('runtime', parts.frameworks)}</div>${parts.runtime && parts.frameworks.length === 0 ? '<p>No declared framework metadata in the saved project graph. Refresh explicitly with architecture:generate.</p>' : ''}</fieldset>\n <fieldset class=\"wp-fgroup\"><legend>Role <small>any match</small></legend><div class=\"wp-chips\">${chips('role', parts.roles)}</div></fieldset>\n ${this.productGroup(parts.products)}\n <footer><button type=\"button\" class=\"wp-text-btn\" id=\"wp-filter-clear\">Clear all</button><button type=\"button\" class=\"wp-primary\" id=\"wp-filter-apply\">Show all ${parts.runtime ? 'services' : 'projects'}</button></footer>\n </div>`;\n }\n\n /**\n * The Product group (#1179): one chip per declared product, each with its palette swatch. Several\n * chips select the UNION of their members; the group intersects with the others. Omitted when the\n * workspace declares no product.\n */\n private productGroup(products: ProductColor[]): string {\n if (products.length === 0) return '';\n const chips = products\n .map(\n (color: ProductColor): string =>\n `<button type=\"button\" class=\"wp-chip\" data-wp-chip-group=\"product\" data-wp-chip=\"${color.product}\" aria-pressed=\"false\">` +\n `<svg class=\"wp-chip-swatch\" width=\"10\" height=\"10\" viewBox=\"0 0 10 10\" aria-hidden=\"true\"><circle cx=\"5\" cy=\"5\" r=\"4.5\" fill=\"${color.color}\"/></svg>` +\n `${color.product}</button>`,\n )\n .join('');\n return `<fieldset class=\"wp-fgroup\" id=\"wp-product-group\"><legend>Product <small>any match</small></legend><div class=\"wp-chips\">${chips}</div></fieldset>`;\n }\n\n /**\n * Which Impact scan the page shows (#1163): \"Changed on this branch\" (fork point → working tree)\n * or \"Last commit\" (HEAD^ → working tree). Hidden until the page finds TWO scans in the sidecar;\n * `where` tells the drawer's copy (shown only in Impact mode) from the Filter popover's.\n */\n private impactKinds(where: string): string {\n return (\n `<div class=\"wp-chips wp-impact-kinds\" data-wp-impact-kinds=\"${where}\" role=\"group\" aria-label=\"Compare\" hidden>` +\n '<button type=\"button\" class=\"wp-chip\" data-wp-impact-kind=\"branch\" aria-pressed=\"false\">Changed on this branch</button>' +\n '<button type=\"button\" class=\"wp-chip\" data-wp-impact-kind=\"commit\" aria-pressed=\"false\">Last commit</button></div>'\n );\n }\n\n private topbar(parts: ShellParts): string {\n return `<div class=\"wp-topbar\">\n <button type=\"button\" class=\"wp-icon\" id=\"wp-collapse\" aria-label=\"Toggle the controls drawer\" aria-controls=\"wp-side\" aria-expanded=\"true\">☰</button>\n <div class=\"wp-crumb\" id=\"wp-crumb\">Mode: <b>Runtime</b></div>\n <div class=\"wp-pills\" id=\"wp-filter-pills\" aria-label=\"Active filters\"></div>\n ${parts.filterStatus}\n <button type=\"button\" class=\"wp-icon\" id=\"wp-help-btn\" aria-label=\"How to read this graph\" aria-controls=\"wp-help\" aria-expanded=\"false\">?</button>\n </div>`;\n }\n\n private overlays(parts: ShellParts): string {\n return `${parts.emptyState}<div class=\"wp-pop wp-legend-popout\" id=\"wp-legend-popout\" hidden>\n <header><span id=\"wp-legend-pop-title\">Legend · Runtime</span><button type=\"button\" class=\"wp-icon wp-icon-mini\" id=\"wp-legend-close\" aria-label=\"Close the legend\">✕</button></header>\n ${parts.legend}\n </div>\n ${this.help(parts.runtime)}\n ${this.filterPopover(parts)}\n <div class=\"wp-pop wp-snapshot\" id=\"wp-snapshot\" hidden>${parts.snapshot}</div>\n <aside class=\"wp-panel\" id=\"wp-resp-panel\" aria-label=\"Responsibilities\" hidden>\n <header><span>Responsibilities</span><button type=\"button\" class=\"wp-icon wp-icon-mini\" id=\"wp-resp-close\" aria-label=\"Close responsibilities\">✕</button></header>\n ${parts.responsibilities}\n </aside>`;\n }\n\n /** The two hint paragraphs that used to sit above the graph, plus the keyboard shortcuts. */\n private help(runtime: boolean): string {\n if (runtime) return `<div class=\"wp-pop wp-help\" id=\"wp-help\" role=\"dialog\" aria-label=\"How to read this graph\" hidden>\n <header><span>Reading the runtime graph</span><button type=\"button\" class=\"wp-icon wp-icon-mini\" id=\"wp-help-close\" aria-label=\"Close help\">✕</button></header>\n <p>Rows preserve saved runtime call-depth levels. Boxes are services; horizontal cylinders are queues, upright cylinders datastores, and clocks scheduled triggers. Solid arrows are RPC calls, dashed arrows queued events; red arrows admit legacy cycles.</p>\n <p>Click a box for Lock, Filter Unconnected, or Implements. Implements in the box is a plain summary. Click Uses on a relationship line for its complete details. Hover traces chains without opening details.</p>\n <p>Lock pins separate incoming and outgoing chains; hover adds another chain temporarily. Hide unconnected removes unrelated boxes independently. Clear all clears facets, leaving Lock and chain filtering intact.</p>\n <p>Filters intersect declared runtime, role, product closure and Nx build scope. Counts describe services; attached contextual nodes are counted separately. Impact uses compile-project sets, never runtime reachability. Queues and vendors are context, never source owners or CI projects.</p>\n <p>Runtime uses declared framework colors, Architecture declared roles; contextual nodes keep their kind colors. Product colors come from each project's declared product: tags; contextual nodes inherit adjacent memberships. Unknown metadata is neutral. Missing saved metadata requires explicit architecture:generate.</p>\n <p><strong>Goal vs Current</strong> compares the saved goal (architecture/runtime-dependencies-goal.json) with the saved current graph, Current → Goal: green added, red dashed removed (still drawn), amber changed, grey unchanged. Click a box for its before/after details, or click an arrow.</p>\n <p><kbd>/</kbd> Focus search · <kbd>1</kbd>–<kbd>5</kbd> modes · <kbd>Esc</kbd> dismiss or unlock</p>\n </div>`;\n return `<div class=\"wp-pop wp-help\" id=\"wp-help\" role=\"dialog\" aria-label=\"How to read this graph\" hidden>\n <header><span>Reading the graph</span><button type=\"button\" class=\"wp-icon wp-icon-mini\" id=\"wp-help-close\" aria-label=\"Close help\">✕</button></header>\n <p>Every row is one dependency level: the HIGHEST level is the top row and L0, the foundation libraries, is always the bottom row. Servers, clients and apps always form the top row (a bundle sits above the apps it aggregates). Transitive dependencies are allowed but not drawn.</p>\n <p>💡 <strong>Click any box</strong> for its menu: <strong>View Design</strong> (only where the project has a generated <strong>design.html</strong>, i.e. what the AI sees inside it), <strong>Lock/Unlock</strong> (the same lock as the Focus field), <strong>Filter Unconnected</strong> (removes unrelated boxes, keeping each L-number row).</p>\n <p><strong>Filter</strong> narrows the graph by what changed on this branch or in the last commit, by runtime, by role and by product; the groups combine. A product keeps its servers, clients and apps plus everything they depend on, so <strong>Product</strong> + <strong>Changed + dependents + dependencies</strong> is exactly what this branch builds that can affect that product. Every box keeps its own L-row, and a level left empty shows as a thin labeled band.</p>\n <p>🔦 <strong>Hover any box</strong> to trace its <em>entire</em> dependency chain — every ancestor above it and every dependency below it, with the lines between — while the rest of the graph dims.</p>\n <p><strong>Runtime</strong>: a box may depend on a box carrying every color it has. <strong>Architecture</strong>: what each box is in the system. <strong>Impact</strong>: what changed on this branch or in the last commit (amber), its dependents (amber outline), and what nx marked for another reason: an input glob (violet hatch) or a root file (teal). Click an affected box for why; with both available, a toggle picks which. <strong>Product</strong>: which products each box belongs to — one color per product, stripes for several, grey for every product, a dashed white box for none.</p>\n <p><kbd>/</kbd> focus the lock search · <kbd>1</kbd> <kbd>2</kbd> <kbd>3</kbd> <kbd>4</kbd> switch mode · <kbd>Esc</kbd> unlock</p>\n </div>`;\n }\n\n private brandIcon(): string {\n return (\n '<svg width=\"22\" height=\"22\" viewBox=\"0 0 22 22\" aria-hidden=\"true\">' +\n '<rect x=\"1\" y=\"1\" width=\"8\" height=\"6\" rx=\"1.5\" fill=\"none\" stroke=\"#a46bf7\" stroke-width=\"1.6\"/>' +\n '<rect x=\"13\" y=\"1\" width=\"8\" height=\"6\" rx=\"1.5\" fill=\"none\" stroke=\"#e9eaf0\" stroke-width=\"1.6\"/>' +\n '<rect x=\"7\" y=\"15\" width=\"8\" height=\"6\" rx=\"1.5\" fill=\"none\" stroke=\"#e9eaf0\" stroke-width=\"1.6\"/>' +\n '<path d=\"M5 7v4h12V7M11 11v4\" fill=\"none\" stroke=\"#e9eaf0\" stroke-width=\"1.6\"/></svg>'\n );\n }\n}\n"]}
|
|
1
|
+
{"version":3,"file":"graph-page-shell.js","sourceRoot":"","sources":["../../../../../../packages/tooling/nx-webpieces-rules/src/lib/graph-page-shell.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * The architecture page's shell (#1155): a collapsible dark drawer on the left holding every control,\n * and the graph filling the rest of the viewport.\n *\n * Before this, two hint paragraphs, a ~650px three-column legend, a lock dropdown and a zoom bar all\n * sat ABOVE the graph, so a laptop's first screen showed no graph at all. Now the hints are a \"?\"\n * popover, the legend lives in the drawer (and can pop out over the graph), zoom floats bottom-right\n * (graph-navigation.ts) and the responsibilities open in a right-hand panel.\n *\n * Markup only. Behaviour is graph-visualizer.client.ts; styling is graph-page-styles.ts. No element\n * carries a `style=` attribute — every look is a class.\n */\n\nimport { FRAMEWORK_ORDER, GRAPH_MODES, GraphMode, ModeInfo, ROLE_STYLES, RoleStyle, RUNTIME_GRAPH_MODES } from './graph-color-modes';\nimport { ProductColor } from './graph-products';\n\n/**\n * The Filter popover's \"Changes on this branch\" choices. The page computes each set from the Impact\n * sidecar (graph-impact.ts): CHANGED = touched; DEPENDENTS = every project nx affected, whatever its reason (their\n * tests re-run); DEPENDENCIES = touched + every transitive dependency of it; BUILD = touched +\n * every affected project + every build input — the dependencies of the DEPENDENTS too, which is why it is more than\n * the union of the two rows above it.\n *\n * \"Dependents\" are what USE a project and \"dependencies\" what it uses (#1179). \"Dependee\" would mean\n * the thing depended ON — the opposite of the dependents row — so it is never used.\n */\nexport enum ChangeScope {\n EVERYTHING = 'everything',\n CHANGED = 'changed',\n DEPENDENTS = 'dependents',\n DEPENDENCIES = 'dependencies',\n BUILD = 'build',\n /** #1264: the boxes at either end of an edge gained or lost since the fork point. */\n EDGES = 'edges',\n}\n\n/**\n * One change scope: its name and the grey second line under it, like the Color-by menu. These are the\n * ONE copy of the labels — the page script reads each name back from its `data-wp-scope-label` (the\n * top-bar pill), so the two cannot drift apart.\n */\nexport class ScopeOption {\n constructor(\n public readonly scope: ChangeScope,\n public readonly label: string,\n public readonly subtitle: string,\n ) {}\n}\n\nexport const SCOPE_OPTIONS: readonly ScopeOption[] = [\n new ScopeOption(ChangeScope.EVERYTHING, 'All', 'every project'),\n new ScopeOption(ChangeScope.CHANGED, 'Changed', 'owns a changed file'),\n new ScopeOption(ChangeScope.DEPENDENTS, 'Changed + dependents', '+ everything else nx affected: dependents, implicitly and root-file touched (their tests re-run)'),\n new ScopeOption(ChangeScope.DEPENDENCIES, 'Changed + dependencies', '+ everything they use'),\n new ScopeOption(ChangeScope.BUILD, 'Changed + dependents + dependencies', 'everything CI builds for this branch'),\n new ScopeOption(ChangeScope.EDGES, 'Edge changes only', 'projects that gained or lost a dependency or call since the fork point'),\n];\n\n/** Everything the shell frames, already rendered by its owner. */\nexport class ShellParts {\n constructor(\n public readonly title: string,\n public readonly lockControl: string,\n public readonly legend: string,\n public readonly edgeKey: string,\n public readonly filterStatus: string,\n public readonly snapshot: string,\n public readonly responsibilities: string,\n /**\n * One chip per product (#1179), sorted, each colored from the page's ONE palette (#1244);\n * empty hides the Filter's Product group.\n */\n public readonly products: ProductColor[],\n public readonly runtime: boolean = false,\n public readonly frameworks: readonly string[] = FRAMEWORK_ORDER,\n public readonly roles: readonly string[] = ROLE_STYLES.map((style: RoleStyle): string => style.role),\n public readonly emptyState: string = '',\n ) {}\n}\n\nexport class GraphPageShell {\n body(parts: ShellParts): string {\n return `<div class=\"wp-shell\" id=\"wp-shell\">\n ${this.drawer(parts)}\n <main class=\"wp-main\">\n ${this.topbar(parts)}\n <div id=\"graph\"></div>\n ${this.overlays(parts)}\n </main>\n</div>`;\n }\n\n private drawer(parts: ShellParts): string {\n return `<aside class=\"wp-side\" id=\"wp-side\" aria-label=\"Graph controls\">\n <div class=\"wp-brand\">${this.brandIcon()}<span>${parts.title}</span></div>\n <div class=\"wp-group\" role=\"group\" aria-label=\"Color mode\">\n <div class=\"wp-label\">Color by</div>\n ${this.modePulldown(parts.runtime ? RUNTIME_GRAPH_MODES : GRAPH_MODES)}\n <p class=\"wp-mode-reason\" id=\"wp-impact-reason\" hidden></p>\n ${this.impactKinds('drawer')}\n </div>\n <div class=\"wp-group\">\n <button type=\"button\" class=\"wp-filter-btn\" id=\"wp-filter-open\" aria-controls=\"wp-filter-pop\" aria-expanded=\"false\"><span>Filter</span><span class=\"wp-badge\" id=\"wp-filter-badge\" hidden>0</span></button>\n </div>\n <div class=\"wp-group\">\n <label class=\"wp-label\" for=\"wp-lock\">Focus</label>\n ${parts.lockControl}\n <button type=\"button\" class=\"wp-toggle\" id=\"wp-lock-toggle\" aria-pressed=\"false\">Lock <span class=\"wp-sw\" aria-hidden=\"true\"></span></button>\n <button type=\"button\" class=\"wp-toggle\" id=\"wp-filter-toggle\" aria-pressed=\"false\">Hide unconnected <span class=\"wp-sw\" aria-hidden=\"true\"></span></button>\n </div>\n <div class=\"wp-group\">\n <div class=\"wp-label wp-label-row\">Legend <button type=\"button\" class=\"wp-icon wp-icon-mini wp-icon-dark\" id=\"wp-legend-pop\" title=\"Pop the legend out over the graph\" aria-label=\"Pop the legend out over the graph\">⇱</button></div>\n ${parts.legend}\n </div>\n <div class=\"wp-group\">\n <div class=\"wp-label\">Edges</div>\n ${parts.edgeKey}\n </div>\n <div class=\"wp-foot\">\n <button type=\"button\" class=\"wp-link\" id=\"wp-resp-open\" aria-expanded=\"false\">Responsibilities</button>\n <button type=\"button\" class=\"wp-link\" id=\"wp-snapshot-open\" aria-expanded=\"false\">Saved snapshot</button>\n </div>\n </aside>`;\n }\n\n /**\n * \"Color by\": ONE pill-shaped trigger showing the current mode (name + subtitle) that opens a\n * menu of the four. Keys 1/2/3/4 and the #runtime / #architecture / #impact / #product links still\n * switch.\n */\n private modePulldown(modes: readonly ModeInfo[]): string {\n const first = modes[0];\n return `<div class=\"wp-pulldown\">\n <button type=\"button\" class=\"wp-pill-trigger\" id=\"wp-mode-trigger\" aria-haspopup=\"menu\" aria-controls=\"wp-mode-menu\" aria-expanded=\"false\">\n <span class=\"wp-pill-text\"><span class=\"wp-mode-name\" id=\"wp-mode-current\">${first.name}</span><span class=\"wp-mode-sub\" id=\"wp-mode-current-sub\">${first.subtitle}</span></span><span class=\"wp-caret\" aria-hidden=\"true\">▾</span>\n </button>\n <div class=\"wp-menu\" id=\"wp-mode-menu\" role=\"menu\" aria-label=\"Color by\" hidden>${modes.map((info: ModeInfo, index: number): string => this.modeItem(info, index)).join('')}</div>\n </div>`;\n }\n\n /** One menu option, two lines: the mode's name, then its grey subtitle. */\n private modeItem(info: ModeInfo, index: number): string {\n const checked = info.mode === GraphMode.RUNTIME ? 'true' : 'false';\n return (\n `<button type=\"button\" class=\"wp-mode\" role=\"menuitemradio\" data-wp-mode=\"${info.mode}\" aria-checked=\"${checked}\" title=\"Key ${index + 1}\">` +\n `<span class=\"wp-mode-name\">${info.name}</span><span class=\"wp-mode-sub\">${info.subtitle}</span></button>`\n );\n }\n\n /**\n * The Filter popover. Its four groups INTERSECT: a box is shown when it is in the chosen change\n * scope AND carries any selected runtime chip (when any is selected) AND any selected role chip\n * (when any is selected) AND belongs to any selected product (when any is selected). Nothing\n * applies until \"Show N projects\".\n */\n private filterPopover(parts: ShellParts): string {\n const scopes = SCOPE_OPTIONS.map(\n (option: ScopeOption): string =>\n `<label class=\"wp-scope\"><input type=\"radio\" name=\"wp-scope\" value=\"${option.scope}\"${option.scope === ChangeScope.EVERYTHING ? ' checked' : ''}>` +\n `<span class=\"wp-scope-text\"><span class=\"wp-scope-name\" data-wp-scope-label=\"${option.scope}\">${option.label}</span>` +\n `<span class=\"wp-scope-sub\">${parts.runtime && option.scope === ChangeScope.EVERYTHING ? 'every service' : option.subtitle}</span></span>` +\n `<span class=\"wp-count\" data-wp-scope-count=\"${option.scope}\"></span></label>`,\n ).join('');\n const chips = (group: string, values: readonly string[]): string =>\n values\n .map(\n (value: string): string =>\n `<button type=\"button\" class=\"wp-chip\" data-wp-chip-group=\"${group}\" data-wp-chip=\"${value}\" aria-pressed=\"false\">${value}</button>`,\n )\n .join('');\n return `<div class=\"wp-pop wp-filter-pop\" id=\"wp-filter-pop\" role=\"dialog\" aria-label=\"Filter ${parts.runtime ? 'services' : 'projects'}\" hidden>\n <header><span>Filter</span><button type=\"button\" class=\"wp-icon wp-icon-mini\" id=\"wp-filter-close\" aria-label=\"Close the filter\">✕</button></header>\n <fieldset class=\"wp-fgroup\" id=\"wp-scope-group\"><legend id=\"wp-scope-legend\">Changes on this branch</legend>${this.impactKinds('filter')}${scopes}<p class=\"wp-scope-reason\" id=\"wp-scope-reason\" hidden></p></fieldset>\n <fieldset class=\"wp-fgroup\"><legend>Runtime <small>any match</small></legend><div class=\"wp-chips\">${chips('runtime', parts.frameworks)}</div>${parts.runtime && parts.frameworks.length === 0 ? '<p>No declared framework metadata in the saved project graph. Refresh explicitly with architecture:generate.</p>' : ''}</fieldset>\n <fieldset class=\"wp-fgroup\"><legend>Role <small>any match</small></legend><div class=\"wp-chips\">${chips('role', parts.roles)}</div></fieldset>\n ${this.productGroup(parts.products)}\n <footer><button type=\"button\" class=\"wp-text-btn\" id=\"wp-filter-clear\">Clear all</button><button type=\"button\" class=\"wp-primary\" id=\"wp-filter-apply\">Show all ${parts.runtime ? 'services' : 'projects'}</button></footer>\n </div>`;\n }\n\n /**\n * The Product group (#1179): one chip per declared product, each with its palette swatch. Several\n * chips select the UNION of their members; the group intersects with the others. Omitted when the\n * workspace declares no product.\n */\n private productGroup(products: ProductColor[]): string {\n if (products.length === 0) return '';\n const chips = products\n .map(\n (color: ProductColor): string =>\n `<button type=\"button\" class=\"wp-chip\" data-wp-chip-group=\"product\" data-wp-chip=\"${color.product}\" aria-pressed=\"false\">` +\n `<svg class=\"wp-chip-swatch\" width=\"10\" height=\"10\" viewBox=\"0 0 10 10\" aria-hidden=\"true\"><circle cx=\"5\" cy=\"5\" r=\"4.5\" fill=\"${color.color}\"/></svg>` +\n `${color.product}</button>`,\n )\n .join('');\n return `<fieldset class=\"wp-fgroup\" id=\"wp-product-group\"><legend>Product <small>any match</small></legend><div class=\"wp-chips\">${chips}</div></fieldset>`;\n }\n\n /**\n * Which Impact scan the page shows (#1163): \"Changed on this branch\" (fork point → working tree)\n * or \"Last commit\" (HEAD^ → working tree). Hidden until the page finds TWO scans in the sidecar;\n * `where` tells the drawer's copy (shown only in Impact mode) from the Filter popover's.\n */\n private impactKinds(where: string): string {\n return (\n `<div class=\"wp-chips wp-impact-kinds\" data-wp-impact-kinds=\"${where}\" role=\"group\" aria-label=\"Compare\" hidden>` +\n '<button type=\"button\" class=\"wp-chip\" data-wp-impact-kind=\"branch\" aria-pressed=\"false\">Changed on this branch</button>' +\n '<button type=\"button\" class=\"wp-chip\" data-wp-impact-kind=\"commit\" aria-pressed=\"false\">Last commit</button></div>'\n );\n }\n\n private topbar(parts: ShellParts): string {\n return `<div class=\"wp-topbar\">\n <button type=\"button\" class=\"wp-icon\" id=\"wp-collapse\" aria-label=\"Toggle the controls drawer\" aria-controls=\"wp-side\" aria-expanded=\"true\">☰</button>\n <div class=\"wp-crumb\" id=\"wp-crumb\">Mode: <b>Runtime</b></div>\n <div class=\"wp-pills\" id=\"wp-filter-pills\" aria-label=\"Active filters\"></div>\n ${parts.filterStatus}\n <button type=\"button\" class=\"wp-icon\" id=\"wp-help-btn\" aria-label=\"How to read this graph\" aria-controls=\"wp-help\" aria-expanded=\"false\">?</button>\n </div>`;\n }\n\n private overlays(parts: ShellParts): string {\n return `${parts.emptyState}<div class=\"wp-pop wp-legend-popout\" id=\"wp-legend-popout\" hidden>\n <header><span id=\"wp-legend-pop-title\">Legend · Runtime</span><button type=\"button\" class=\"wp-icon wp-icon-mini\" id=\"wp-legend-close\" aria-label=\"Close the legend\">✕</button></header>\n ${parts.legend}\n </div>\n ${this.help(parts.runtime)}\n ${this.filterPopover(parts)}\n <div class=\"wp-pop wp-snapshot\" id=\"wp-snapshot\" hidden>${parts.snapshot}</div>\n <aside class=\"wp-panel\" id=\"wp-resp-panel\" aria-label=\"Responsibilities\" hidden>\n <header><span>Responsibilities</span><button type=\"button\" class=\"wp-icon wp-icon-mini\" id=\"wp-resp-close\" aria-label=\"Close responsibilities\">✕</button></header>\n ${parts.responsibilities}\n </aside>`;\n }\n\n /** The two hint paragraphs that used to sit above the graph, plus the keyboard shortcuts. */\n private help(runtime: boolean): string {\n if (runtime) return `<div class=\"wp-pop wp-help\" id=\"wp-help\" role=\"dialog\" aria-label=\"How to read this graph\" hidden>\n <header><span>Reading the runtime graph</span><button type=\"button\" class=\"wp-icon wp-icon-mini\" id=\"wp-help-close\" aria-label=\"Close help\">✕</button></header>\n <p>Rows preserve saved runtime call-depth levels. Boxes are services; horizontal cylinders are queues, upright cylinders datastores, and clocks scheduled triggers. Solid arrows are RPC calls, dashed arrows queued events; red arrows admit legacy cycles.</p>\n <p>Click a box for Lock, Filter Unconnected, or Implements. Implements in the box is a plain summary. Click Uses on a relationship line for its complete details. Hover traces chains without opening details.</p>\n <p>Lock pins separate incoming and outgoing chains; hover adds another chain temporarily. Hide unconnected removes unrelated boxes independently. Clear all clears facets, leaving Lock and chain filtering intact.</p>\n <p>Filters intersect declared runtime, role, product closure and Nx build scope. Counts describe services; attached contextual nodes are counted separately. Impact uses compile-project sets, never runtime reachability. Queues and vendors are context, never source owners or CI projects.</p>\n <p>Runtime uses declared framework colors, Architecture declared roles; contextual nodes keep their kind colors. Product colors come from each project's declared product: tags, painted for the products toggled ON in the legend (the first two on every load); contextual nodes inherit adjacent memberships. Unknown metadata is neutral. Missing saved metadata requires explicit architecture:generate.</p>\n <p><strong>Goal vs Current</strong> compares the saved goal (architecture/runtime-dependencies-goal.json) with the saved current graph, Current → Goal: green added, red dashed removed (still drawn), amber changed, grey unchanged. Click a box for its before/after details, or click an arrow.</p>\n <p><kbd>/</kbd> Focus search · <kbd>1</kbd>–<kbd>5</kbd> modes · <kbd>Esc</kbd> dismiss or unlock</p>\n </div>`;\n return `<div class=\"wp-pop wp-help\" id=\"wp-help\" role=\"dialog\" aria-label=\"How to read this graph\" hidden>\n <header><span>Reading the graph</span><button type=\"button\" class=\"wp-icon wp-icon-mini\" id=\"wp-help-close\" aria-label=\"Close help\">✕</button></header>\n <p>Every row is one dependency level: the HIGHEST level is the top row and L0, the foundation libraries, is always the bottom row. Servers, clients and apps always form the top row (a bundle sits above the apps it aggregates). Transitive dependencies are allowed but not drawn.</p>\n <p>💡 <strong>Click any box</strong> for its menu: <strong>View Design</strong> (only where the project has a generated <strong>design.html</strong>, i.e. what the AI sees inside it), <strong>Lock/Unlock</strong> (the same lock as the Focus field), <strong>Filter Unconnected</strong> (removes unrelated boxes, keeping each L-number row).</p>\n <p><strong>Filter</strong> narrows the graph by what changed on this branch or in the last commit, by runtime, by role and by product; the groups combine. A product keeps its servers, clients and apps plus everything they depend on, so <strong>Product</strong> + <strong>Changed + dependents + dependencies</strong> is exactly what this branch builds that can affect that product. Every box keeps its own L-row, and a level left empty shows as a thin labeled band.</p>\n <p>🔦 <strong>Hover any box</strong> to trace its <em>entire</em> dependency chain — every ancestor above it and every dependency below it, with the lines between — while the rest of the graph dims.</p>\n <p><strong>Runtime</strong>: a box may depend on a box carrying every color it has. <strong>Architecture</strong>: what each box is in the system. <strong>Impact</strong>: what changed on this branch or in the last commit (amber), its dependents (amber outline), and what nx marked for another reason: an input glob (violet hatch) or a root file (teal). Click an affected box for why; with both available, a toggle picks which. <strong>Product</strong>: which products each box belongs to. Toggle products in the legend (the first two are ON on every load): one ON product is its color, several ON are stripes, only OFF products are light grey, neutral means every product while all are ON, and a dashed white box belongs to none.</p>\n <p><kbd>/</kbd> focus the lock search · <kbd>1</kbd> <kbd>2</kbd> <kbd>3</kbd> <kbd>4</kbd> switch mode · <kbd>Esc</kbd> unlock</p>\n </div>`;\n }\n\n private brandIcon(): string {\n return (\n '<svg width=\"22\" height=\"22\" viewBox=\"0 0 22 22\" aria-hidden=\"true\">' +\n '<rect x=\"1\" y=\"1\" width=\"8\" height=\"6\" rx=\"1.5\" fill=\"none\" stroke=\"#a46bf7\" stroke-width=\"1.6\"/>' +\n '<rect x=\"13\" y=\"1\" width=\"8\" height=\"6\" rx=\"1.5\" fill=\"none\" stroke=\"#e9eaf0\" stroke-width=\"1.6\"/>' +\n '<rect x=\"7\" y=\"15\" width=\"8\" height=\"6\" rx=\"1.5\" fill=\"none\" stroke=\"#e9eaf0\" stroke-width=\"1.6\"/>' +\n '<path d=\"M5 7v4h12V7M11 11v4\" fill=\"none\" stroke=\"#e9eaf0\" stroke-width=\"1.6\"/></svg>'\n );\n }\n}\n"]}
|
|
@@ -80,6 +80,9 @@ class GraphPageStyles {
|
|
|
80
80
|
.wp-legend-row { display: flex; align-items: center; gap: 10px; line-height: 1.25; }
|
|
81
81
|
.wp-legend-row svg { flex: none; }
|
|
82
82
|
.wp-legend-row small { display: block; color: var(--wp-side-muted); font-size: 11.5px; }
|
|
83
|
+
.wp-product-toggle { cursor: pointer; }
|
|
84
|
+
.wp-product-toggle input { flex: none; margin: 0; accent-color: var(--wp-accent); cursor: pointer; }
|
|
85
|
+
.wp-product-note { margin: 2px 0 0; font-size: 11.5px; color: var(--wp-side-muted); }
|
|
83
86
|
.wp-impact-note { margin: 2px 0 0; font-size: 11.5px; color: var(--wp-side-muted); }
|
|
84
87
|
.wp-impact-note:empty { display: none; }
|
|
85
88
|
.wp-foot { margin-top: auto; padding: 10px 18px 0; border-top: 1px solid var(--wp-side-line); display: flex; gap: 14px; flex-wrap: wrap; }`;
|
|
@@ -164,7 +167,7 @@ class GraphPageStyles {
|
|
|
164
167
|
border-radius: 10px; box-shadow: 0 8px 24px #0002; padding: 12px 14px; font-size: 13px; box-sizing: border-box; }
|
|
165
168
|
.wp-pop header { display: flex; justify-content: space-between; align-items: center; gap: 8px; font-weight: 600; margin-bottom: 8px; }
|
|
166
169
|
.wp-legend-popout { left: 12px; bottom: 12px; width: 270px; max-height: 60vh; overflow: auto; }
|
|
167
|
-
.wp-legend-popout .wp-legend-row small, .wp-legend-popout .wp-impact-note { color: var(--wp-muted); }
|
|
170
|
+
.wp-legend-popout .wp-legend-row small, .wp-legend-popout .wp-impact-note, .wp-legend-popout .wp-product-note { color: var(--wp-muted); }
|
|
168
171
|
.wp-help { right: 12px; top: 56px; width: min(380px, calc(100% - 24px)); line-height: 1.5; }
|
|
169
172
|
.wp-help p { margin: 0 0 8px; }
|
|
170
173
|
.wp-snapshot { left: 12px; bottom: 12px; width: min(440px, calc(100% - 24px)); }
|