@vendure/admin-ui-plugin 2.0.0-next.26 → 2.0.0-next.27
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/lib/admin-ui/430.4469edebdd7335b3.js.map +1 -1
- package/lib/admin-ui/625.b3ffd6dd39d19338.js.map +1 -1
- package/lib/admin-ui/index.html +1 -1
- package/lib/admin-ui/{main.d521c77cc07c4f33.js → main.c25877ffe4ebfda0.js} +2 -2
- package/lib/admin-ui/{main.d521c77cc07c4f33.js.map → main.c25877ffe4ebfda0.js.map} +1 -1
- package/package.json +4 -4
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"mappings":"mpEAOQA,oBAGIA,iDAASC,SAGTD,8BACJA,gCAHIA,8DAEAA,+GCQL,iBACKE,MAMRC,YACIC,EACAC,EACAC,EACQC,EACEC,EACFC,GAERC,MAAML,EAAOD,EAAQE,EAAqBE,GAJlCG,2BACEA,mBACFA,mBATZA,gBAAa,IAAIC,KAAU,IAYvBD,KAAKE,aAAeF,KAAKG,qBAAqB,SAGlDC,WACIJ,KAAKK,WAAa,IAAIJ,KAAU,CAC5BK,KAAM,IAAIL,KAAY,IACtBM,KAAM,IAAIN,KAAY,IACtBC,aAAcF,KAAKQ,YAAYC,MAC3BT,KAAKE,aAAaQ,OAAO,CAACjB,EAAMC,IAAUiB,+BAAMlB,GAAI,EAAGC,EAAMY,MAAO,KAAO,OAGnFN,KAAKY,OAGTC,cACIb,KAAKc,UAGTC,cAActB,WACiB,QAA3BC,OAAKW,WAAWW,IAAI,eAAO,SAAEC,SAASxB,EAAMa,MACjB,QAA3BX,OAAKU,WAAWW,IAAI,eAAO,SAAEC,SAASxB,EAAMc,MAC5CP,KAAKK,WAAWa,cAGpB5B,OACIU,KAAKmB,YAAYC,QACZC,YAAY,CACTC,GAAItB,KAAKsB,GACThB,KAAMN,KAAKK,WAAWkB,MAAMjB,KAC5BC,KAAMP,KAAKK,WAAWkB,MAAMhB,KAC5BL,aAAcF,KAAKK,WAAWkB,MAAMrB,eAEvCsB,UACG,KACIxB,KAAKyB,oBAAoBC,SAAQ,OAAE,gCAAiC,CAAEC,OAAQ,WAElFlC,IACIO,KAAKyB,oBAAoBG,OAAM,OAAE,8BAA+B,CAC5DD,OAAQ,YAMlBE,cAAcpC,EAA6CC,WACtC,QAA3BC,OAAKU,WAAWW,IAAI,eAAO,SAAEC,SAASxB,EAAOa,MAClB,QAA3BV,OAAKS,WAAWW,IAAI,eAAO,SAAEC,SAASxB,EAAOc,MACzCP,KAAKE,aAAa4B,QAClB9B,KAAK+B,yBAAyB/B,KAAKE,aAAcF,KAAKK,WAAWW,IAAI,CAAC,iBAAkBvB,2CAhEvFuC,IAAoB3C,sGAApB2C,GAAoBC,6UDrBjC5C,0BAAgB,iBAERA,8CACJA,QAEAA,wBACIA,kCACAA,2BAQJA,UAEJA,+BAKIA,uCAAeK,sCAClBL,eArBwBA,8CAMZA,gDAUTA,6CAAyB,cAAzBA,CAAyB,8BAAzBA,CAAyB,gcEQtB,iBACKE,MAaRC,YACYC,EACAC,EACAC,EACRC,EACAC,GAEAE,MAAMH,EAAQC,GANNG,2BACAA,oBACAA,mBATZA,iBAAc,IAAIkC,SAAoC,GACtDlC,mBAAgB,IAAIkC,SAA2C,GAC/DlC,gBAAY,EAYRD,MAAMoC,WACF,IAAIrC,IAAgBE,KAAKmB,YAAYC,QAAQgB,gBAAgBtC,GAC7DA,GAAQA,EAAKuC,OACb,CAACvC,EAAMwC,WACH,MAAMC,EAAavC,KAAKwC,YAAYjB,MAC9BkB,EAA+B,QAAxBC,OAAKC,cAAcpB,aAAK,eAAEqB,IAAIC,GAAKA,EAAEtB,OAClD,MAAO,CACHuB,QAAOnC,6BACHoC,OACAC,QACIT,EACE,CACIU,OAAQ,CACJ3C,KAAM,CAAE4C,SAAUX,KAG1B,IAAG,CACTY,KAAM,CACFC,UAAW7D,YAEfgB,OACA8C,aAAc9D,cAI1B,CAAEyD,KAAM,GAAID,KAAM,IAI1B3C,WACIL,MAAMK,WACNJ,KAAKsD,mBAAoB,OAActD,KAAKuD,cAAevD,KAAKwD,aAAcxD,KAAKyD,aAAaC,QAC5FC,KAAI,EAAElE,EAAcC,EAAaC,MAAiB,CAAEiE,eAAcC,cAAaC,iBAEnF9D,KAAKwC,YAAYkB,MAAK,OAAa,MAAM,OAAU1D,KAAK+D,WAAWvC,UAAU,IAAMxB,KAAKgE,WAExFhE,KAAK2C,cAAce,MAAK,OAAU1D,KAAK+D,WAAWvC,UAAU,IAAMxB,KAAKgE,WACvEhE,KAAKiE,SAAWjE,KAAKmB,YAAYC,QAAQ8C,aAAaC,UAAU1E,GAAQA,EAAKc,KAAK6D,OAGtFC,cAAc5E,GACNA,EAAMqC,SACN9B,KAAKsE,WAAY,EACjBtE,KAAKmB,YAAYC,QACZmD,aAAa9E,GACbiE,QAAKc,MAAS,IAAOxE,KAAKsE,WAAY,IACtC9C,UAAU,EAAG+C,mBACV,IAAI5E,EAAe,EACnB,UAAWC,KAAUF,EACjB,OAAQE,EAAO6E,gBACN,QACD9E,IACA,UACC,gBACDK,KAAKyB,oBAAoBG,MAAMhC,EAAO8E,SAI9C,EAAI/E,IACJI,MAAMiE,UACNhE,KAAKyB,oBAAoBC,SAAQ,OAAE,sCAAuC,CACtEiD,MAAOhF,QAO/BiF,aAAanF,GACTO,KAAK6E,mBAAmBpF,EAAOmD,IAAIlD,GAAKA,EAAE4B,KACrCoC,MACG,OAAUhE,GACFA,EAASoF,SAAWvF,cACb,EAAC,GAEDS,KAAK6E,mBACRpF,EAAOmD,IAAIjD,GAAKA,EAAE2B,IAClB5B,EAASgF,SAAW,IACtBhB,QAAKC,KAAIhE,GAAKA,EAAEmF,SAAWvF,kBAIxCiC,UACG,KACIxB,KAAKyB,oBAAoBC,SAAQ,OAAE,gCAAiC,CAChEC,OAAQ,WAEZ3B,KAAKgE,WAETtE,IACIM,KAAKyB,oBAAoBG,OAAM,OAAE,8BAA+B,CAC5DD,OAAQ,aAMpBkD,mBAAmBpF,EAAoBC,GAC3C,OAAOM,KAAK+E,aACPC,OAAO,CACJC,SAAOC,KAAE,iCACTC,gBAAiB,CACbR,MAAOlF,EAASqC,QAEpBsD,KAAM1F,EACN2F,QAAS,CACL,CAAEC,KAAM,YAAaC,SAAOL,KAAE,kBAC9B,CAAEI,KAAM,SAAUC,OAAO,OAAE,iBAAkBC,aAAa,MAGjE9B,QACG+B,KAAU9F,GAAQA,EAAMK,KAAKmB,YAAYC,QAAQwD,aAAanF,IAAYC,GAAWgG,MACrF,OAAI/F,GAAOA,EAAIiF,uDAtIlBe,IAAkBtG,0FAAlBsG,GAAkB1D,qbC1B/B5C,0BAAgB,kBAAhBA,CAAgB,8BAKJA,4CAAoBK,uBAApBL,CAA6C,gCAC/BK,2CACjBL,UAELA,wBACIA,kCACAA,kCACIA,uCAAeK,qBAGlBL,YAITA,+BAIIA,wCAAgBK,qGACnBL,QAEDA,kBAA6B,oCAGrBA,8CAAsBK,yCACzBL,QAEDA,sCAIIA,sCAAcK,2EACjBL,iBApCYA,0BAGLA,8CASAA,wCAORA,yGAA0E,iBAA1EA,CAA0E,uCAQtEA,4DAKAA,0DAAoC,4CAApCA,CAAoC,yuBC9BhCA,kBAGIA,0DAASO,0DAHbP,iCAEIA,gGAGJA,kBAAgDA,kDAASuG,iBACrDvG,uBACAA,eAAKA,8BAA6CA,gBAA7CA,8EAIOA,kDACxBA,kBAA+D,eACvCA,kDAASuG,iBACzBvG,uBACAA,8BACJA,gBADIA,gFAlBZA,iBAAqD,UAArDA,CAAqD,WAGzCA,wBAKAA,wBAIJA,UAEJA,iBAAwBA,iCAA2DA,QACnFA,yBAMJA,yCAjBiBA,uCAIqBA,wCAMKA,qCACbA,iGAUtBA,kBAGIA,0DAASO,0DAHbP,iCAEIA,gGAIJA,kBAAgDA,kDAASuG,iBAAgBvG,uBAA8CA,+BAE3HA,kDACAA,qBAIIA,kDAASuG,sCAETvG,uBACAA,8BACJA,cALIA,4CAIAA,gFAjBJA,kBACIA,wBAMAA,wBACJA,QACAA,iCACAA,6DARSA,uCAKqBA,wCAEfA,qCAEVA,iGAYDA,kBAOIA,uDAAsBA,EAAtBwG,OAAsBC,8CAEtBzG,2BAAsB,YAQdA,0CACJA,QACAA,gCAA8C,eACJA,2DAASA,EAATwG,OAASE,kBAC3C1G,8BACJA,QACAA,sBAIIA,2DAASA,EAATwG,OAASG,6CAET3G,gCACJA,QACAA,mBACAA,sBAKIA,2DAASA,EAATwG,OAASI,2CAET5G,gCACJA,+DAnCRA,2BAAyB,wDAQjBA,2CAIKA,iDAIDA,oDAIAA,8EAIAA,mEAOAA,6DAGAA,qFAxCpBA,kBACIA,2BA4CJA,8BA7CwBA,2BAEEA,oCCXvB,QAiBHG,YAAoBC,EAAoCC,GAApCM,oBAAoCA,sBARxDA,cAAU,EACAA,YAAS,IAAIX,MAEhBW,YAAkB,GAXJkG,iBAAazG,GAE9BO,KAAKqC,QAAU5C,GAAO,IAAI0G,QAgB9BP,eACI5F,KAAK+E,aACAqB,cAAc7G,MAA4B,CACvC8G,KAAM,OAET7E,UAAU/B,IACHA,GAAUA,EAAOqC,SACjB9B,KAAKqC,UAASiE,KAAOtG,KAAKqC,OAAOkE,OAAO9G,GAAS,MAC5CO,KAAKwG,gBACNxG,KAAKwG,cAAgB/G,EAAO,IAEhCO,KAAKyG,gBAAgBzG,KAAKqC,OAAQrC,KAAKwG,eACvCxG,KAAK0G,eAAeC,kBAKpCX,cAAcvG,GACVO,KAAKwG,cAAgB/G,EACrBO,KAAKyG,gBAAgBzG,KAAKqC,OAAQ5C,GAGtCmH,WAAWnH,GACP,QAASO,KAAKwG,eAAiBxG,KAAKwG,cAAclF,KAAO7B,EAAM6B,GAGnEyE,aAAatG,GACTO,KAAK+E,aACAqB,cAAc7G,KAA6B,CACxC8G,KAAM,KACNQ,UAAU,EACVC,OAAQ,CAAEC,WAEbvF,YAGTyE,YAAYxG,GACRO,KAAKqC,OAASrC,KAAKqC,OAAOY,OAAOvD,GAAKA,EAAE4B,KAAO7B,EAAM6B,IACjDtB,KAAKwG,eAAiBxG,KAAKwG,cAAclF,KAAO7B,EAAM6B,KACtDtB,KAAKwG,cAAgBxG,KAAKqC,OAAOP,OAAS,EAAI9B,KAAKqC,OAAO,QAAK,GAEnErC,KAAKyG,gBAAgBzG,KAAKqC,OAAQrC,KAAKwG,eAGnCC,gBAAgBhH,EAAiBC,GACrCM,KAAKgH,OAAOC,KAAK,CACb5E,SACAmE,kBAIRV,gBAAgBrG,IACZ,QAAgBO,KAAKqC,OAAQ5C,EAAMyH,kBAAkBC,KAAM1H,EAAM2H,UAAUD,MAC3EnH,KAAKyG,gBAAgBzG,KAAKqC,OAAQrC,KAAKwG,sDAxElCa,GAAehI,oDAAfgI,EAAepF,2lDDrC5B5C,wBAuBAA,2CAsBAA,kEA7CmBA,yBAAgB,o3EEE3BA,iIAsBIA,gBAA8BA,SAAkBA,QAChDA,gBAA8B,aAAmBA,SAAiBA,UAClEA,gBACIA,wDAKJA,6BAR8BA,uBACmBA,sBAIzCA,iDAAmC,yFCUhD,SAqBHG,YAAoBC,EAA+BC,EAAwBC,GAAvDK,aAA+BA,cAAwBA,mBAhBlEA,4BAAwB,EAOjCA,uBAAoB,IAAIC,KAAY,IACpCD,gBAAY,EACJA,yBAAsB,IAAIkC,IAAwB,IAClDlC,qBAAkB,IAAIkC,IAAwB,IAC9ClC,oBAAiB,IAAIkC,IAA8C,IACnElC,4BAAyB,IAAIkC,KAAyB,GACtDlC,cAAW,IAAIkC,KAAyB,GACxClC,cAAW,IAAIsH,KAIvBlH,WACIJ,KAAKuH,qBAAuBvH,KAAKwH,MAAMC,cAAc/D,QACjDC,KAAI7D,GAAOA,EAAIkB,IAAI,oBACnB2C,KAAI7D,GAAUA,GAAYA,EAAL,IACrB,QAAU,IACV,UAGJE,KAAK0H,sBAAwB1H,KAAKwH,MAAMC,cAAc/D,QAClDC,KAAI7D,GAAOA,EAAIkB,IAAI,qBACnB,OAAIlB,GAAYA,GAAiBA,EAAN,KAC3B,QAAU,OACV6H,QAGJ,MAAMlI,EAAcO,KAAK4H,kBAAkBC,aAAanE,MACpD,OAAa,QACboE,KAAI,IAAM9H,KAAK+H,sBAAsB,OACrCC,MAAU,KAGRtI,EAAiBM,KAAKiI,eAAeC,eAAexE,QACtDyE,MAAO,IAAMnI,KAAKoI,0BAClBN,KAAI,IAAM9H,KAAK+H,sBAAsB,KACrC,QAAU,KAGRpI,EAAyBK,KAAKqI,uBAAuBH,eAAexE,MACtE,QAAO,IAA6B,MAAvB1D,KAAKsI,mBAClBX,QACA,OAAI,IAAM3H,KAAK+H,sBAAsB,OACrCC,OAAU,IAcRnI,GAXe,OACjBG,KAAKuI,oBACLvI,KAAKwI,gBACLxI,KAAKuH,qBACLvH,KAAK0H,sBACLjI,EACAC,EACAC,EACAK,KAAKyI,UAGwB/E,MAC7B,OAAU1D,KAAK+D,aACf+D,KAAI,IAAO9H,KAAK0I,WAAY,IAC5B,OAAa,KACb,OAAU,EAAE5I,EAAIwC,EAAUI,EAAaH,EAAcE,EAAYI,EAAS8F,MACtE,MAAMC,EAAOrG,EACPsG,GAAQnG,EAAc,GAAKH,EACjC,GAAIM,EAAQf,QAAU9B,KAAKoI,sBAAuB,CAC9C,MAAMU,EAAerG,EACd,CAAEnC,KAAM,CAAE4C,SAAUT,SACrB,EACN,OAAOzC,KAAKmB,YAAY4H,WACnBC,0BACG,CACIC,WACAC,UACAZ,kBAEJ,CACItF,OACAD,OACAE,OAAQ6F,IAGfK,UAAUC,GAAQA,EAAKJ,2BACvBtF,MAAK,QAAW,KAAM,QAAG,CAAEU,MAAO,GAAIN,WAAY,MACpD,OAAIhE,EACAE,KAAKmB,YAAY4H,WACnBM,sBAAsBvJ,EAAI8I,EAAMC,EAAMpG,GACtC0G,UAAUL,IAAO,MAAC,OAAe,QAAfM,IAAKL,kBAAU,eAAEO,qBAEjCC,MAAG,SAGlB,OAAI,IAAOvJ,KAAK0I,WAAY,IAC5B,QAAS,IAAO1I,KAAK0I,WAAY,IAGrC1I,KAAKwJ,UAAY3J,EAAY6D,QAAKC,KAAI7D,GAAWA,EAASA,EAAOsE,MAAQ,KACzEpE,KAAKyJ,oBAAsB5J,EAAY6D,MAAK,OAAI5D,GAAWA,EAASA,EAAOgE,WAAa,IAG5F4F,YAAYjK,GACJ,iBAAkBA,GAClBO,KAAKuI,oBAAoBoB,KAAKlK,EAAQmK,aAAaC,cAEnD,aAAcpK,GACdO,KAAKwI,gBAAgBmB,KAAKlK,EAAQwJ,SAASY,cAE3C,mBAAoBpK,GACpBO,KAAKqI,uBAAuBsB,KAAKlK,EAAQ6I,eAAeuB,cAExD,mBAAoBpK,GAChBO,KAAK8J,gBACL9J,KAAKiI,eAAe0B,KAAK3J,KAAK8J,gBAK1CjJ,cACIb,KAAK+D,SAAS4F,OACd3J,KAAK+D,SAASgG,WAGlBhC,sBAAsBtI,GAClBO,KAAKgK,SAAS,eAAgBvK,GAGlCwK,wBAAwBxK,GACpBO,KAAKgK,SAAS,kBAAmBvK,GAGrCuE,UACIhE,KAAKyI,SAASkB,MAAK,GAGfK,SAASvK,EAAaC,GAC1BM,KAAKkK,OAAOC,SAAS,CAAC,MAAO,CACzBC,WAAYpK,KAAKwH,MACjB6C,YAAa,EACR5K,GAAMC,GAEX4K,oBAAqB,QACrBC,YAAY,4CAvJXC,IAA2BnL,gEAA3BmL,GAA2BvI,uFAMtB5C,MAAW,iqBD7C7BA,iBAA6B,WAErBA,kDAGJA,QACAA,wCAKJA,QACAA,iBACIA,iBACAA,4BAMIA,sCAAcK,4BAAdL,CAA4C,wCACtBK,sGAEtBL,gCAWJA,iBA/BSA,oDAAkC,0EAKvCA,mEAAoD,mCAK7BA,sCAEvBA,sCACAA,uCAA2B,oDAA3BA,CAA2B,gDAA3BA,CAA2B,ikCEH3BA,oBAGIA,iDAASoL,WAGTpL,8BACJA,gCAHIA,8DAEAA,6FAGAA,oBAGIA,kDAASC,SAGTD,8BACJA,iCAHIA,oFAEAA,6EANJA,gDACKA,yHAeDA,gBAA2DA,8BAA2CA,eAAnGA,gCAAwDA,uIAC3DA,gBAAsFA,8BAAiCA,wCAApHA,qCAAmFA,6DACtFA,SAA6BA,8BAAiCA,wCAAjCA,6DAHjCA,cACIA,uBACAA,uBACAA,kCACJA,uCAHgDA,yBACeA,8BAC5CA,iDAgBPA,SAA6DA,8BAEvDA,eAFuDA,oEAGvCA,8IA+BlCA,sBAAkE,WACvDA,8BAAwCA,QAC/CA,gEAMJA,+BAPWA,kDAGHA,8CAA6B,sDAA7BA,CAA6B,mEAiCzBA,SAAsEA,8BAEpEA,eAFoEA,yFAG9CA,gIAOhCA,SACIA,qCACIA,wDAAUA,EAAVwG,OAAU6E,2CAMbrL,QACLA,yDANQA,6BAAc,cAAdA,CAAc,+CAAdA,CAAc,oBAAdA,CAAc,qFAgBdA,qBAIIA,2DAASA,EAATwG,OAAS8E,eAETtL,SACJA,oCADIA,iEAbhBA,eAA0C,iBAA1CA,CAA0C,eAG9BA,uBACAA,8BACJA,QACAA,gCACIA,4BAQJA,mCAXIA,6DAIuBA,4JAqB3BA,kBACIA,mDAGJA,QACAA,gCAA6E,cAOrEA,0DAAiBuL,sBANrBvL,QAQAA,iBAAOA,8BAAiDA,yDAbxDA,yHAIkBA,iFAIdA,8CAAuC,iEAAvCA,CAAuC,yBAKpCA,8IA/J/BA,kBAAkF,UAAlFA,CAAkF,WAItEA,wBAKJA,UAEJA,kBAAqB,WAArBA,CAAqB,4CAGTA,8BACIA,8CAOAA,qBACIA,mCAGAA,6CACJA,YAGRA,oDACIA,qBAKIA,0CAASA,EAATwG,MAASgF,uDALbxL,UAQJA,0EAKIA,+CAMJA,QACAA,oFAMAA,8BASAA,gDAKJA,QACAA,mBAA6B,oBAKrBA,oEACHA,YAGTA,mBAAqB,YAArBA,CAAqB,YAENA,gCAAmCA,QAC1CA,oDACIA,+BACIA,+CAOAA,qBACIA,mCAGAA,6CAGJA,YAGRA,mBACIA,mCAUJA,QAEAA,0BAkBJA,QACAA,mBAAqB,0FASbA,gCAkBJA,uEAlKOA,gCAIoBA,wCASXA,yDAOJA,+DAGeA,kDAAgC,cAO3CA,mDAKRA,4DAKJA,oDAAoC,iEAQhCA,4DAKJA,4DAAgD,2CAIbA,6CAWnCA,oCAAmB,2BAMnBA,kCAA4B,gCAA5BA,CAA4B,wCASzBA,+CACSA,kEAOJA,+DAGeA,yDAAuC,cAU7BA,oCAAY,4BAY3CA,sDAqBFA,oCAAmB,oCAAnBA,CAAmB,gDAAnBA,CAAmB,gDAAnBA,CAAmB,wCC3H5B,iBACKE,MAgBRC,YACIC,EACAC,EACAC,EACQC,EACEC,EACFC,EACAwC,EACAI,EACAH,SAERxC,MAAML,EAAOD,EAAQE,EAAqBE,GAPlCG,sBACEA,mBACFA,mBACAA,2BACAA,oBACAA,2BApBZA,kBAA4D,GAC5DA,aAAmC,GACnCA,gBAAgD,GAGhDA,kBAAc,EAELA,sBAAmB,CAACT,oBAA0BA,wBAC/CS,oBAAiB,IAAIsH,KAezBtH,KAAKE,aAAeF,KAAKG,qBAAqB,cAC9CH,KAAKK,WAAaL,KAAKQ,YAAYC,MAAM,CACrCH,KAAM,CAAC,GAAIL,eACX6K,KAAM,CAAC,MAAIvL,OAAwB,yBACnCwL,YAAa,GACbC,SAAS,EACT1C,gBAAgB,EAChBY,QAASlJ,KAAKQ,YAAYyK,MAAM,IAChC/K,aAAcF,KAAKQ,YAAYC,MAC3BT,KAAKE,aAAaQ,OAAO,CAACmC,EAAM8F,IAAUhI,+BAAMkC,GAAI,EAAG8F,EAAMrI,MAAO,KAAO,OAGnFN,KAAKkL,YAA2E,QAA7DzI,OAAK0I,oBAAoBnK,IAAI,wCAAgC,SAGpFZ,WACIJ,KAAKY,OACLZ,KAAKmB,YAAY4H,WAAWqC,uBAAuBC,QAAQ7J,UAAU7B,IACjEK,KAAKsL,WAAa3L,EAAI4L,oBAE1B,MAAM9L,EAAmBO,KAAKK,WAAWW,IAAI,WACvCtB,EAAwBM,KAAKK,WAAWW,IAAI,kBAClDhB,KAAKwL,gBAAkB9L,EAAsBmI,aAAanE,MAAK,UAC/D1D,KAAKyL,iBAAkB,QAAMhM,EAAiBiM,cAAe1L,KAAK2L,gBAAgBjI,QAC9EkI,KAAa,MACb,QAAO,IAAMnM,EAAiBoM,UAC9B,OAAI,IACA7L,KAAK8L,sBAAsB9L,KAAKkJ,QAASzJ,EAAiB8B,OAAO0B,OAAOtD,IAGpE,UAAWC,KAAOD,EAAQoM,UACtB,GAAkB,KAAdnM,EAAI2B,MACJ,OAAO,EAGf,OAAO,MAInBvB,KAAKgM,UAAYhM,KAAKwH,MAAMyE,SAASvI,QACjCC,KAAIhE,GAAMA,EAAGqB,IAAI,kBAAe,IAChC,OAAUrB,GACFA,GACO,QAAGA,GAEHK,KAAKkM,QAAQxI,MAAK,OAAI9D,IAAa,MAAC,OAAiB,QAAjBC,IAAWsM,cAAM,eAAE7K,QAM9ET,cACIb,KAAKc,UAGTsL,oBAAoB3M,GAChB,OAAOO,KAAKsL,WAAWe,KAAK3M,GAAKA,EAAE4M,OAAS7M,EAAQ6M,MAGxDC,gBACI,QAAS5L,OAAO6L,OAAOxM,KAAKyM,cAAc3K,OAM9C+I,WAAWpL,IACP,OAAcO,KAAKkM,QAASlM,KAAK0M,eAC5BhJ,QAAKiJ,KAAK,IACVnL,UAAU,EAAE9B,EAAQC,MACjB,MAAMC,EAAcI,KAAKK,WAAWW,IAAI,CAAC,SACnCnB,KAAqBN,OAAgBG,EAAQC,GAC7CG,GAAsBD,IAAuBA,EAAmBiL,KAClElL,GAAeA,EAAYgN,UAAY9M,GACvCF,EAAYqB,UAAS,QAAgB,GAAGxB,IAAa,QAKrEkL,UAAUlL,GACN,MAAMC,EAAeM,KAAKK,WAAWW,IAAI,WACnCrB,EAAWF,EAAiBoN,KAAKnM,OACnC,CAACd,EAAQC,IAAQc,+BACVf,GAAM,EACRC,EAAIS,OAAO,SAAkBT,EAAI0B,SAEtC,IAEJ7B,EAAaoN,KACT9M,KAAKQ,YAAYuM,QAAQ,CACrBT,KAAM7M,EAAiB6M,KACvBO,KAAMlN,KAGdK,KAAKkJ,QAAQ4D,KAAK,CACdR,KAAM7M,EAAiB6M,KACvBO,KAAMpN,EAAiBoN,KAAKjK,IAAIhD,IAAM,CAAEU,KAAMV,EAAEU,KAAMiB,OAAO,SAAkB3B,EAAE2B,YAIzFmJ,aAAajL,GACT,MAAMC,EAAeM,KAAKK,WAAWW,IAAI,YAC3B,IAAVvB,IACAC,EAAasN,SAASvN,GACtBC,EAAawB,cACbxB,EAAauN,gBACbjN,KAAKkJ,QAAQgE,OAAOzN,EAAO,GAC3BO,KAAK2L,eAAehC,QAI5Bc,UACSzK,KAAKK,WAAW8M,UAGrBC,KAAcpN,KAAKkM,QAASlM,KAAK0M,eAC5BhJ,MACG,OAAK,IACL,OAAS,EAAEjE,EAAUC,MACjB,MAAMC,EAAQK,KAAKqN,qBACf5N,EACAO,KAAKK,WACLX,GAEEE,EAAWI,KAAKwH,MAAM8F,SAASrB,SAASjL,IAAI,YAClD,OAAIpB,IACAD,EAAMsJ,SAAWrJ,GAEdI,KAAKmB,YAAY4H,WAAWwE,iBAAiB5N,MAG3D6B,UACG/B,IACIO,KAAKyB,oBAAoBC,SAAQ,OAAE,gCAAiC,CAChEC,OAAQ,eAEZ3B,KAAKyM,aAAe,GACpBzM,KAAKK,WAAWmN,iBAChBxN,KAAK0G,eAAeC,eACpB3G,KAAKkK,OAAOC,SAAS,CAAC,MAAO1K,EAAK8N,iBAAiBjM,IAAK,CAAE8I,WAAYpK,KAAKwH,SAE/E/H,IACIO,KAAKyB,oBAAoBG,OAAM,OAAE,8BAA+B,CAC5DD,OAAQ,iBAM5BrC,UACI8N,KAAcpN,KAAKkM,QAASlM,KAAK0M,eAC5BhJ,MACG,OAAK,IACL,OAAS,EAAEjE,EAAUC,MACjB,MAAMC,EAAQK,KAAKqN,qBACf5N,EACAO,KAAKK,WACLX,GAEJ,OAAOM,KAAKmB,YAAY4H,WAAW0E,iBAAiB9N,MAG3D6B,UACG,KACIxB,KAAKyM,aAAe,GACpBzM,KAAKK,WAAWmN,iBAChBxN,KAAK0G,eAAeC,eACpB3G,KAAKyB,oBAAoBC,SAAQ,OAAE,gCAAiC,CAChEC,OAAQ,eAEZ3B,KAAK0N,kBAAkB1J,WAE3BvE,IACIO,KAAKyB,oBAAoBG,OAAM,OAAE,8BAA+B,CAC5DD,OAAQ,iBAM5BgM,gBACI,OAAO5N,MAAM4N,kBAAoB3N,KAAKyM,aAAapK,SAAWrC,KAAKyM,aAAajG,cAGpFoE,oBACI5K,KAAKkL,aAAelL,KAAKkL,YACzBlL,KAAKmL,oBAAoByC,IAAI,gCAAiC5N,KAAKkL,aAGvE2C,UAAUpO,EAAeC,GACrB,OAAOoO,KAAKC,UAAUrO,GAMhBmC,cAAcpC,EAA4BC,GAChD,MAAMC,GAAqB,SAAgBF,EAAQC,GAEnDM,KAAKK,WAAW2N,WAAW,CACvB1N,KAAMX,EAAqBA,EAAmBW,KAAO,GACrDwK,KAAMnL,EAAqBA,EAAmBmL,KAAO,GACrDC,YAAapL,EAAqBA,EAAmBoL,YAAc,GACnEC,SAAUvL,EAAOwO,UACjB3F,eAAgB7I,EAAO6I,iBAG3B,MAAM1I,EAAYI,KAAKK,WAAWW,IAAI,WAClCpB,EAAUkC,SAAWrC,EAAOyJ,QAAQpH,SACpClC,EAAUsO,QACVlO,KAAKkJ,QAAU,GACfzJ,EAAOyJ,QAAQiF,QAAQtO,GAAKG,KAAK2K,UAAU9K,KAG3CG,KAAKE,aAAa4B,QAClB9B,KAAK+B,yBACD/B,KAAKE,aACLF,KAAKK,WAAWW,IAAI,CAAC,iBACrBvB,EACAE,GASJ0N,qBACJ5N,EACAC,EACAC,WAEA,MAAMG,KAAkBP,OAA0B,CAC9C6O,aAAc3O,EACd4O,cAAe3O,EAAK6B,MACpB+M,kBAAmBtO,KAAKE,aACxBqO,eACAC,mBAAoB,CAChBD,eACAjO,KAAMb,EAASa,MAAQ,GACvBwK,KAAMrL,EAASqL,MAAQ,GACvBC,YAAatL,EAASsL,aAAe,MAG7C,sCACOjL,GAAe,CAClB2O,SAAkC,QAAxB7O,OAAK6M,aAAapK,cAAM,eAAEO,IAAIN,GAAKA,EAAEhB,IAC/CoN,gBAAgD,QAA/B7O,OAAK4M,aAAajG,qBAAa,eAAElF,GAClD2M,WAAYvO,EAAK6B,MAAMyJ,QACvB9B,QAASlJ,KAAK8L,sBAAsB9L,KAAKkJ,QAASlJ,KAAKK,WAAWkB,MAAM2H,WAOxE4C,sBACJrM,EACAC,GAEA,OAAOD,EAAWmD,IAAI,CAACjD,EAAGC,KACf,CACH0M,KAAM3M,EAAE2M,KACRP,UAAWpL,OAAOgO,QAAQjP,EAAoBE,GAAGiN,MAAMjK,IAAI,EAAE/C,EAAMC,GAAQwC,KAChE,CACHhC,OACAiB,SAAOhC,OAAqBO,iDAxSvC8O,IAAyBvP,6IAAzBuP,GAAyB3M,2uED/CtC5C,0BAAgB,iBAERA,8CACAA,mCAIIA,8CAAsBK,sEACzBL,UAGLA,wBACIA,kCACAA,8CAQAA,4CAUJA,UAEJA,sEA/ByBA,8CAEbA,+CAA2B,2DAA3BA,CAA2B,mDAW1BA,6CAAsB,cAkBUA,w+BEzBtC,YACHwP,EACApP,EACAC,EAAwB,YAExB,MAAMG,EAAoC,GACpCC,EAA2C,GAC3CwC,EAsCV,YAAwCuM,GACpC,MAAMpP,EAAU,IAAIqP,IACpB,WAAenP,GACXF,EAAQmO,IAAIjO,EAAK2B,GAAI3B,GACrBA,EAAKoP,SAASZ,QAAQzO,GAE1B,OAAImP,GACAnP,EAAMmP,GAEHpP,EA/CiBuP,CAAUvP,GAGlC,UAAW8C,KAAQsM,EACf/O,EAAUyC,EAAKjB,IAAGX,+BAAS4B,GAAY,CAAEwM,SAAU,KAGvD,UAAWxM,KAAMsM,EAAMjM,IAAIH,GAAKA,EAAEnB,IAC9B,GAAIxB,EAAUmP,eAAe1M,GAAK,CAC9B,MAAME,EAAa3C,EAAUyC,GAC7BE,EAAWyM,SAA4C,QAAjCtP,EAAuB,QAAvBD,IAAgBqB,IAAIuB,UAAG,eAAE2M,gBAAQ,QAAIxP,EAAYyP,SAAS5M,GAChF,MAAMM,EAASJ,EAAW0J,OAC1B,IAAKtJ,EACD,SAGkB/C,EAAU+C,EAAOvB,IAEnCxB,EAAc+C,EAAOvB,IACjBxB,EAAU+C,EAAOvB,IAAIyN,SAASjC,KAAKrK,GAEnC3C,EAAU+C,EAAOvB,IAAM,CAAEyN,SAAU,CAACtM,IAGxC5C,EAAciN,KAAKrK,GAM/B,MAAO,CAAEnB,GADMzB,EAAciC,OAASjC,EAAc,GAAGsM,OAAQ7K,QAAK,EAC/CyN,SAAUlP,GCjC5B,QASHL,cARQQ,sBAAqF,GAErFA,iBAAc,IAAIsH,KAClBtH,cAAW,IAAIsH,KAMnBtH,KAAKoP,WAAapP,KAAKqP,YAAYnH,eACnClI,KAAKsP,QAAUtP,KAAKuP,SAASrH,eAGjCrH,cACIb,KAAKqP,YAAYtF,WACjB/J,KAAKuP,SAASxF,WAGlByF,kBAAkB/P,GACdO,KAAKyP,eAAiBhQ,EAG1BiQ,gBACI1P,KAAK2P,iBAAmB,GAG5BC,iBAAiBnQ,GACb,OAAqC,IAAjCO,KAAK2P,iBAAiB7N,SACtB9B,KAAK2P,iBAAmB3P,KAAK6P,6BAE1B7P,KAAK2P,iBAAiB1M,OACzBvD,UACI,SAAK4B,KAAO7B,EAAW6B,KACtB5B,EAAKoQ,eAAeC,IAAItQ,EAAW6B,KACpC5B,EAAK4B,MAAwB,QAAjB3B,IAAWwM,cAAM,eAAE7K,MAI3C0O,OAAOvQ,GACH,MAAMC,EAAOD,EAAMwQ,KAAK9I,KAElBvH,EADYH,EAAM2H,UAAUD,KACJ7F,GAC9B,GAAmB,MAAf1B,EACA,MAAM,IAAIsQ,MAAM,qDAEpBlQ,KAAKqP,YAAY1F,KAAK,CAClBC,aAAclK,EAAK4B,GACnB2H,SAAUrJ,EACVuQ,MAAO1Q,EAAM2Q,eAIrBC,OAAO5Q,GACHO,KAAKqP,YAAY1F,KAAKlK,GAG1B6Q,SAAS7Q,GACLO,KAAKuP,SAAS5F,KAAKlK,GAGfoQ,4BACJ,MAAMpQ,EAAQ,CACVC,EACAC,EACAC,EACAC,KAEA,MAAMC,EAAOH,EAAW4G,OAAO7G,EAAKY,MACpC,SAAOwM,KAAK,CAAEyD,KAAMzQ,EAAKqG,MAAM,GAAGqK,KAAK,QAAU,OAAQlP,GAAI5B,EAAK4B,GAAIwO,mBACtEpQ,EAAKqP,SAASZ,QAAQ7L,GAClB7C,EAAM6C,EAAOxC,EAAM,IAAI2Q,IAAY,IAAI7Q,EAAgBF,EAAK4B,KAAMzB,IAE/DA,GAEX,OAAOJ,EAAMO,KAAKyP,eAAgB,GAAI,IAAIgB,IAAe,2CA3EpDC,gCAAqBC,QAArBD,EAAqB,iDCuBdrR,6CACAA,gEAPJA,qBAIIA,2EAASuR,oBAETvR,8BACAA,8BACJA,oDANIA,8BAI0BA,iDACKA,sEAG/BA,yCAKRA,oBAAuCA,8BAAmCA,eAAnCA,qEAavCA,kBACIA,uBACJA,oHAMQA,gBAKIA,uBACAA,8BACJA,wCALIA,iDAIAA,6GAwBJA,qBAIIA,+EAASA,EAATwG,MAASgL,gCAGTxR,kBAA0B,YAElBA,uBACJA,QACAA,kBACIA,SACJA,mDARJA,qDAOQA,yDAiBxBA,gFAEIA,+BAAuB,mBAAvBA,CAAuB,0CAAvBA,CAAuB,+TAtH/BA,iBAMC,UANDA,CAMC,QANDA,CAMC,aAWeA,4DAASA,EAATwG,MAASiL,wCAJbzR,UAOJA,iBACIA,2BASAA,2CAGAA,SACJA,QACAA,iBACAA,+BACAA,iBAKIA,wBACAA,gCACJA,QACAA,iBACIA,wBACAA,gCACJA,QACAA,0BAGAA,yBAAc,gBACqCA,mEAASuQ,sBACpDvQ,wBACJA,QACAA,iCACIA,wBAQAA,mBACAA,sBAIIA,yEAASA,EAATwG,MAASkL,gCAET1R,wBACAA,gCACJA,QACAA,sBAMIA,yEAASA,EAATwG,MAASmL,kCAET3R,wBACAA,gCACJA,QACAA,kBAA4BA,gCAAmCA,QAC/DA,6BAgBAA,mBACAA,sBAGIA,2DAASA,EAATwG,MAASoL,iCAGT5R,wBACAA,gCACJA,cAIZA,+CAOJA,mEAzHIA,6BAGAA,uBAKIA,qDADAA,kCAOQA,2DAQCA,+DAAmC,cASxCA,+BAGOA,mCAGPA,4DAIAA,6DAE2BA,+CAE3BA,mDAEoCA,gDAW3BA,gDASDA,uEAIAA,uDAKAA,wGAMAA,yDAEwBA,+CAIPA,0CAkBjBA,gEAGAA,qDAMXA,gDCjGN,QAYHG,YACoCC,EACxBC,EACAC,EACAC,EACAC,EACAC,GALwBE,cACxBA,mBACAA,6BACAA,cACAA,aACAA,yBAjBZA,WAAQ,EAICA,gBAAY,EAIrBA,mBAAqD,GAW7CP,IACAO,KAAKkR,MAAQzR,EAAOyR,MAAQ,GAIpC9Q,iBACIJ,KAAKmR,WAAanR,KAAKyP,eAAenP,MAAQ,SAC9C,MAAMZ,EAAeM,KAAKmB,YAAYiQ,OACjCC,aACAlN,UAAUxE,GAAQA,EAAK0R,WAAWC,aAClC5N,QAAK6N,MAAY,IACtBvR,KAAKwR,qBAAuB9R,EAAagE,QACrCC,KACIhE,GACIA,EAAMwP,SAAS5P,sBAA6BI,EAAMwP,SAAS5P,0BAGvES,KAAKyR,qBAAuB/R,EAAagE,MACrC,OACI/D,GACIA,EAAMwP,SAAS5P,sBAA6BI,EAAMwP,SAAS5P,0BAGvES,KAAK0R,aAAoC,QAArBjS,OAAKqR,wBAAgB,eAAEa,kBAAkBnQ,UAAU,IACnExB,KAAK4R,kBAAkBjL,gBAI/B+C,YAAYjK,GACR,MAAMC,EAAkBD,EAAQoS,UAC5BnS,IACsC,IAAlCA,EAAgBoS,gBAA2D,IAAjCpS,EAAgBmK,cAC1D7J,KAAKyP,eAAeV,SAASZ,QAAQxO,GAAMA,EAAEuP,UAAW,GAKpErO,oBACqB,QAAjBpB,OAAKiS,oBAAY,SAAEK,cAGvBlE,UAAUpO,EAAeC,GACrB,OAAOA,EAAK4B,GAGhBsP,eAAenR,WACXA,EAAWyP,UAAYzP,EAAWyP,SAClC,IAAItP,EAA2E,QAA7DD,EAAiD,QAAjDD,OAAK8H,MAAM8F,SAAS7F,cAAczG,IAAI,mBAAW,eAAEgR,MAAM,YAAI,QAAI,GAC/EvS,EAAWyP,SACXtP,EAAYkN,KAAKrN,EAAW6B,IAE5B1B,EAAcA,EAAYqD,OAAOpD,GAAMA,IAAOJ,EAAW6B,IAE7DtB,KAAKkK,OAAOC,SAAS,CAAC,MAAO,CACzBE,YAAa,CACT6E,SAAUtP,EAAYqD,OAAOpD,KAAQA,GAAI2Q,KAAK,MAElDlG,oBAAqB,QACrBF,WAAYpK,KAAKwH,QAIzBoI,iBAAiBnQ,GACbO,KAAKiS,cAAgBjS,KAAKkS,sBAAsBtC,iBAAiBnQ,GAGrEoR,KAAKpR,EAA+BC,GAChCM,KAAKkS,sBAAsB7B,OAAO,CAC9BF,MAAO,EACPlH,WACAW,aAAcnK,EAAW6B,KAIjCyP,OAAOtR,EAA+BC,IAC7BD,EAAW0M,QAGhBnM,KAAKkS,sBAAsB7B,OAAO,CAC9BF,MAAOzQ,EAAe,EACtBuJ,SAAUxJ,EAAW0M,OAAO7K,GAC5BsI,aAAcnK,EAAW6B,KAIjC0P,SAASvR,EAA+BC,IAC/BD,EAAW0M,QAGhBnM,KAAKkS,sBAAsB7B,OAAO,CAC9BF,MAAOzQ,EAAe,EACtBuJ,SAAUxJ,EAAW0M,OAAO7K,GAC5BsI,aAAcnK,EAAW6B,KAIjC6Q,KAAK1S,IACD,QAAgBO,KAAKyP,eAAeV,SAAUtP,EAAM2S,cAAe3S,EAAM2Q,cACzEpQ,KAAKkS,sBAAsBlC,OAAOvQ,GAGtCwR,OAAOxR,GACHO,KAAKkS,sBAAsB5B,SAAS7Q,6BCtJ5CJ,2DAGIA,+BAAuB,kCAAvBA,CAAuB,sCAAvBA,CAAuB,kFDyBdgT,GAA2BhT,MAaQgT,EAA2B,yFAb9DA,EAA2BpQ,s8DD5BxC5C,mBAMIA,8CAAsBK,6BAEtBL,0BA4HJA,eAhIIA,0CAAkC,0DAOPA,oDAA4B,gICiB9CgT,GAA2BC,m5EELjC,SAUH9S,YAAoBC,gCAPXO,gBAAY,EACZA,iBAAwB,GAEvBA,eAAY,IAAIX,MAChBW,sBAAmB,IAAIX,MAKjCqK,YAAYjK,GACJ,gBAAiBA,GAAWO,KAAKuS,cACjCvS,KAAKyP,eAAiB+C,GAAYxS,KAAKuS,YAAavS,KAAKyP,eAAgBzP,KAAKyS,aAC9EzS,KAAKkS,sBAAsB1C,kBAAkBxP,KAAKyP,gBAClDzP,KAAKkS,sBAAsBxC,iBAInCtP,WACIJ,KAAKkS,sBAAsB9C,WAAW5N,UAAU/B,GAASO,KAAK0S,UAAUzL,KAAKxH,IAC7EO,KAAKkS,sBAAsB5C,QAAQ9N,UAAU/B,GAAMO,KAAK2S,iBAAiB1L,KAAKxH,4CAtBzEmT,IAAuBvT,oCAAvBuT,GAAuB3Q,uRAFrB,CAACyO,IAAsBrR,kQDrBtCA,kDACKA,wJE6BGA,gBAKIA,uBACAA,8BACJA,eAJIA,gCAGAA,mJAgCIA,kBACIA,+CAGJA,QACAA,qBAA2CA,iDAASwT,kBAChDxT,uBACJA,8CANIA,mLClCb,SAaHG,YACYC,EACAC,EACAC,EACAC,EACAC,EACAC,EACAwC,GANAtC,mBACAA,2BACAA,oBACAA,cACAA,aACAA,2BACAA,yBAnBZA,uBAAoB,IAAIC,KAAY,IAMpCD,gBAAY,EACZA,iBAAwB,GAGhBA,cAAW,IAAIsH,KAWnBtH,KAAK8Q,iBAAmB,IAAIvR,MAAiB,CACzCuT,cAAc,EACdC,aAAa,EACbC,cAAe,CAACtQ,EAAGH,IAAMG,EAAEpB,KAAOiB,EAAEjB,KAI5ClB,mBACIJ,KAAKiT,YAAcjT,KAAKmB,YAAY4H,WAAWmK,eAAe,IAAM,GAAGC,yBACvEnT,KAAKoT,OAASpT,KAAKiT,YACd9O,UAAUxE,GAAQA,EAAK4S,YAAYnO,OACnCV,MACG,OAAI/D,GAASK,KAAK8Q,iBAAiBuC,gBAAgB1T,KACnD,QAAY,IAEpBK,KAAKsT,oBAAsBtT,KAAKwH,MAAMyE,SAASvI,MAC3C,OAAI/D,GAAMA,EAAGqB,IAAI,gBACjB2G,QAEJ3H,KAAKyS,YAA2E,QAA7D/S,EAAiD,QAAjDD,OAAK+H,MAAM8F,SAAS7F,cAAczG,IAAI,mBAAW,eAAEgR,MAAM,YAAI,QAAI,GACpFhS,KAAK6R,UAAkE,QAAtD7R,KAAKwH,MAAM8F,SAAS7F,cAAczG,IAAI,YAEvDhB,KAAKuT,wBAAyB,OAAcvT,KAAKsT,oBAAqBtT,KAAKoT,QAAQ1P,MAC/E,OAAI,EAAE/D,EAAIC,MACN,GAAID,EAAI,CACJ,MAAME,EAAQD,EAAYyM,KAAKvM,GAAKA,EAAEwB,KAAO3B,GAC7C,OAAOE,EAAQA,EAAMS,KAAO,GAEhC,MAAO,MAGfN,KAAKwT,oBAAsBxT,KAAKyT,oBAAoBC,wBACpD1T,KAAK2T,iBAAmB3T,KAAKmB,YAAYiQ,OACpCwC,UACAzP,UAAU,EAAGyP,aAAcjU,EAAQkU,iBACnCnQ,QAAKoE,KAAI,IAAM9H,KAAKgE,YAEzBhE,KAAK4H,kBAAkBC,aAClBnE,MAAK,OAAa,MAAM,OAAU1D,KAAK+D,WACvCvC,UAAU7B,IACPK,KAAKkK,OAAOC,SAAS,CAAC,MAAO,CACzBE,YAAa,CACTvC,EAAGnI,QAAQ,GAEf2K,oBAAqB,QACrBF,WAAYpK,KAAKwH,UAI7BxH,KAAKwH,MAAMC,cACN/D,MACG,OAAI/D,GAAOA,EAAIqB,IAAI,SACnB2G,QACA,OAAU3H,KAAK+D,WAElBvC,UAAU,IAAMxB,KAAKgE,WAC1BhE,KAAK4H,kBAAkBoG,WAAWhO,KAAKwH,MAAM8F,SAAS7F,cAAczG,IAAI,MAG5EH,cACIb,KAAKiT,YAAYa,WAAWnK,OAC5B3J,KAAK+D,SAAS4F,UAAK,GACnB3J,KAAK+D,SAASgG,WAGlBgK,kBACI/T,KAAKkK,OAAOC,SAAS,CAAC,MAAO,CACzBE,YAAa,CACT6E,SAAUlP,KAAK6R,UAAY,WAAQ,GAEvCvH,oBAAqB,QACrBF,WAAYpK,KAAKwH,QAIzBwM,YAAYvU,GACRO,KAAKmB,YAAY4H,WAAWkL,eAAe,CAACxU,IAAQ+B,UAAU,CAC1DmI,KAAM,KACF3J,KAAKyB,oBAAoBC,SAAQ,OAAE,gCACnC1B,KAAKgE,WAETpC,MAAOlC,IACHM,KAAKyB,oBAAoBG,SAAMsD,KAAE,wCAK7CyN,iBAAiBlT,GACbO,KAAKoT,OACA1P,QACGiJ,KAAK,MACLhJ,KAAIjE,IAAS,EAAKA,EAAMwU,UAAUvU,GAAKA,EAAEwM,QAAUxM,EAAEwM,OAAO7K,KAAO7B,KACnE,OAAUC,GACCM,KAAK+E,aAAaC,OAAO,CAC5BC,SAAOC,KAAE,qCACTE,KAAM1F,GACA,OAAE,4DACF,EACN2F,QAAS,CACL,CAAEC,KAAM,YAAaC,SAAOL,KAAE,kBAC9B,CAAEI,KAAM,SAAUC,OAAO,OAAE,iBAAkBC,aAAa,QAItE,OAAU9F,GAAaA,EAAWM,KAAKmB,YAAY4H,WAAW4J,iBAAiBlT,GAAMiG,MAExFlE,UACG,KACIxB,KAAKyB,oBAAoBC,SAAQ,OAAE,gCAAiC,CAChEC,OAAQ,eAEZ3B,KAAKgE,WAETtE,IACIM,KAAKyB,oBAAoBG,OAAM,OAAE,8BAA+B,CAC5DD,OAAQ,iBAM5BkR,gBACI,MAAMpT,EAAMkB,iBAAQX,KAAKwH,MAAM8F,SAAS6G,eACjC1U,EAAO2U,SACdpU,KAAKkK,OAAOC,SAAS,CAAC,KAAM1K,GAAS,CAAE2K,WAAYpK,KAAKwH,MAAO8C,oBAAqB,aAGxF+J,YAAY5U,GACRO,KAAKmB,YAAYiQ,OAAOkD,mBAAmB7U,GAAM+B,YAGrDwC,UACI,MAAMvE,EAAaO,KAAKwH,MAAM8F,SAAS7F,cAAczG,IAAI,KACzDhB,KAAKiT,YAAYsB,IAAIC,QAAQ,CACzB1R,QAAOnC,eACHoC,KAAM,EACNC,KAAM,KACFvD,EACE,CACIwD,OAAQ,CACJ3C,KAAM,CACF4C,SAAUzD,KAItB,8CAvKTgV,IAAuBpV,oHAAvBoV,GAAuBxS,q9BDnCpC5C,0BAAgB,gBAAhBA,CAAgB,WAGJA,wCAOAA,iBAAyB,yBAAzBA,CAAyB,aAIgBA,yDAAuB,2BAAWK,sBAAnEL,QACAA,iBACIA,+BACJA,UAEJA,oCAIIA,8CAAsBK,uDACzBL,cAIbA,yBACIA,mCACAA,uBAQJA,UAEJA,kBAAkC,cAK1BA,gCAASK,uCAJbL,QAMAA,oCAMJA,QACAA,mBAAgC,6BAOxBA,qCAAaK,kBAAbL,CAAiC,sCACbK,4DACvBL,QAEDA,qCACIA,yDACIA,+BAUJA,mBAvEQA,kDAAiC,oDAQIA,sCAE7BA,sEAKJA,4EAAsD,uDAW7DA,gDAYLA,0EAMAA,kCAAsB,uCAMtBA,oDAA8B,wDAA9BA,CAA8B,wBAA9BA,CAA8B,4BAA9BA,CAA8B,uCASDA,8DACJA,65CErDzBA,oBAGIA,iDAASoL,WAGTpL,8BACJA,gCAHIA,8DAEAA,6FAGAA,oBAGIA,kDAASC,SAGTD,8BACJA,iCAHIA,8DAEAA,6EANJA,gDACKA,qEAuBGA,SAAmEA,8BAEjEA,eAFiEA,oEAG7CA,sJA0BlCA,sBAAkE,WACvDA,8BAAwCA,QAC/CA,gEAMJA,+BAPWA,kDAGHA,8CAA6B,sDAA7BA,CAA6B,mEAqBzBA,SACIA,cAAIA,8BAAwCA,QAChDA,eADQA,qIAmBRA,iBACIA,gEAOJA,+CALQA,mDAAkC,aAAlCA,CAAkC,wDAAlCA,CAAkC,qFAhB9CA,iBAAwF,WAEhFA,6BACJA,QACAA,iBAAyB,cAKjBA,wEAASA,EAATwG,MAAS6O,qGAJbrV,UAOJA,iBAAyBA,oBAAqDA,QAC9EA,wBASAA,iBAAyB,kBAAzBA,CAAyB,gBAGbA,gCACAA,wBACJA,QACAA,iCAA8C,gBAItCA,uEAASA,EAATwG,MAAS8O,sFAITtV,wBACAA,gCACJA,iEAtCoDA,yBAE3CA,2BAMbA,0DAKMA,kDAYFA,qDAQIA,4DAIAA,gFAlD5BA,oBAAsG,UAAtGA,CAAsG,QAG1FA,cACAA,cAAIA,8BAA+BA,QACnCA,cAAIA,8BAA+BA,QACnCA,mCAGAA,eACJA,UAEJA,kBACIA,2BA2CJA,iCApDYA,yCACAA,yCACWA,kDAOuBA,6EA+C9CA,qBAIIA,kDAASuV,kBAETvV,uBACAA,8BACJA,cADIA,mJAtEZA,sBAAsD,WAC3CA,8BAAwCA,QAE/CA,4BA2DAA,eACIA,4BASJA,iCAvEOA,kDAEwDA,uDA+DtDA,yFA3HjBA,kBAA6E,cAA7EA,CAA6E,4CAGjEA,8BACIA,6CAOAA,oBACIA,kCAGAA,4CACJA,YAGRA,oDACIA,qBAKIA,uDAASA,EAATwG,MAASgP,8DALbxV,UAQJA,8EAKIA,+CAMJA,QAEAA,8BASAA,gDAKJA,QAEAA,gDA0EJA,4CAnImBA,gCAEKA,yDAKJA,8DAKeA,wDAAsC,cAOjDA,mDAKRA,4DAKJA,mDAAmC,kDAO/BA,4DAK+BA,6CAWnCA,oCAAmB,2BAKEA,+CC1D1B,iBACKE,MASRC,YACIC,EACAC,EACAC,EACQC,EACEC,EACFC,EACAwC,EACAI,GAER3C,MAAML,EAAOD,EAAQE,EAAqBE,GANlCG,sBACEA,mBACFA,mBACAA,2BACAA,oBAVHA,sBAAmB,CAACT,oBAA0BA,mBAanDS,KAAKE,aAAeF,KAAKG,qBAAqB,SAC9CH,KAAK8U,kBAAoB9U,KAAKG,qBAAqB,cACnDH,KAAKK,WAAaL,KAAKQ,YAAYC,MAAM,CACrCsU,MAAO/U,KAAKQ,YAAYC,MAAM,CAC1B6L,KAAM,CAAC,GAAIrM,eACXK,KAAM,GACN0K,SAAS,EACT9K,aAAcF,KAAKQ,YAAYC,MAC3BT,KAAKE,aAAaQ,OAAO,CAAC6B,EAAME,IAAU9B,+BAAM4B,GAAI,EAAGE,EAAMnC,MAAO,KAAO,OAGnFkM,OAAQxM,KAAKQ,YAAYyK,MAAM,MAIvC7K,WACIJ,KAAKY,OAGTC,cACIb,KAAKc,UAGT+T,WAAWpV,EAAqBC,GAC5B,IAAKD,EAAa,CACd,MAAME,EAAcK,KAAKK,WAAWW,IAAI,CAAC,QAAS,SAC9CrB,GAAeA,EAAYiN,UAC3BjN,EAAYsB,UAAS,QAAgBvB,EAAW,OAK5DgV,gBAAgBjV,EAAqBC,EAAmBC,GACpD,IAAKF,EAAa,CACd,MAAMG,EAAcI,KAAKK,WAAWW,IAAI,CAAC,SAAUrB,EAAO,SACtDC,GAAeA,EAAYgN,UAC3BhN,EAAYqB,UAAS,QAAgBvB,EAAW,OAK5DsV,sBAAsBvV,EAAeC,GACjC,QAASM,KAAKK,WAAWW,IAAI,CAAC,SAAUvB,EAAO,eAAgBC,IAGnEuV,qBACI,OAAOjV,KAAKK,WAAWW,IAAI,UAG/B4T,gBACI,MAAMnV,EAAkBO,KAAKK,WAAWW,IAAI,UAC5C,GAAIvB,EAAiB,CACjB,MAAMC,EAAaM,KAAKQ,YAAYC,MAAM,CACtCa,GAAI,GACJhB,KAAM,CAAC,GAAIL,eACXqM,KAAM,KAEJ3M,EAAgB,CAAEW,KAAM,GAAIgM,KAAM,IACxC,GAAItM,KAAK8U,kBAAkBhT,OAAQ,CAC/B,MAAMlC,EAAyB,IAAIK,KAAU,IAC7CN,EAASO,aAAe,GAExB,UAAWL,KAAYG,KAAK8U,kBAAmB,CAC3C,MAAMhV,EAAMD,EAASS,KACrBV,EAAuBsV,WAAWpV,EAAK,IAAIG,MAG/CP,EAAWwV,WAAW,eAAgBtV,GAE1CH,EAAgB0V,OAAO1V,EAAgBqC,OAAQpC,GAC/CM,KAAKwM,OAAOM,KAAKnN,IAIzB8K,SACI,MAAMhL,EAAYO,KAAKK,WAAWW,IAAI,UACjCvB,IAAcA,EAAU0N,UAG7BC,KAAcpN,KAAKkM,QAASlM,KAAK0M,eAC5BhJ,MACG,OAAK,IACL,OAAS,EAAEhE,EAAOC,MACd,MAAMC,EAAWI,KAAKoV,gBAClB1V,EACAD,EACAE,GAEJ,OAAOK,KAAKmB,YAAY4T,MAAMM,YAAYzV,MAE9C,OAAUF,GAAQM,KAAKmB,YAAY4T,MAAMO,eAAejK,QAAQ3H,MAAK,QAAMhE,MAE9E8B,UACG9B,IACIM,KAAKyB,oBAAoBC,WAAQwD,KAAE,gCAAiC,CAAEvD,OAAQ,UAC9E3B,KAAKK,WAAWmN,iBAChBxN,KAAK0G,eAAeC,eACpB3G,KAAKkK,OAAOC,SAAS,CAAC,MAAOzK,EAAK2V,YAAY/T,IAAK,CAAE8I,WAAYpK,KAAKwH,SAE1E9H,IACIM,KAAKyB,oBAAoBG,OAAM,OAAE,8BAA+B,CAC5DD,OAAQ,YAM5BrC,UACI8N,KAAcpN,KAAKkM,QAASlM,KAAK0M,eAC5BhJ,MACG,OAAK,IACL,OAAS,EAAEjE,EAAOC,MACd,MAAMC,EAAaK,KAAKK,WAAWW,IAAI,SACjCpB,EAA2C,GAEjD,GAAID,GAAcA,EAAWwN,MAAO,CAChC,MAAMrN,EAAWE,KAAKoV,gBAClB3V,EACAE,EACAD,GAEAI,GACAF,EAAiBkN,KAAK9M,KAAKmB,YAAY4T,MAAMQ,YAAYzV,IAGjE,MAAMD,EAAcG,KAAKK,WAAWW,IAAI,UACxC,GAAInB,GAAeA,EAAYsN,MAAO,CAClC,MAAMrN,EAAgBE,KAAKwV,sBACvB/V,EACAI,EACAH,GAEAI,EAAcgC,QACdlC,EAAiBkN,KACb9M,KAAKmB,YAAY4T,MACZU,kBAAkB3V,GAClB4D,QAAK+B,KAAU,IAAMzF,KAAKmB,YAAY4T,MAAMW,SAAS1V,KAAKsB,IAAI+J,WAG3E,MAAM/I,EAAgBtC,KAAK2V,sBACvBlW,EACAI,EACAH,GAEA4C,EAAcR,QACdlC,EAAiBkN,KAAK9M,KAAKmB,YAAY4T,MAAMa,kBAAkBtT,IAIvE,SAAOuT,KAASjW,QAEpB6F,KAAU,IAAMzF,KAAKmB,YAAY4T,MAAMO,eAAejK,UAEzD7J,UACG,KACIxB,KAAKK,WAAWmN,iBAChBxN,KAAK0G,eAAeC,eACpB3G,KAAKyB,oBAAoBC,SAAQ,OAAE,gCAAiC,CAAEC,OAAQ,WAElFlC,IACIO,KAAKyB,oBAAoBG,OAAM,OAAE,8BAA+B,CAC5DD,OAAQ,YAM5BgT,iBAAiBlV,EAAkCC,GAC/C,IAAKD,EAAc,CAEf,MAAME,EAAkBK,KAAKK,WAAWW,IAAI,UAK5C,OAJIrB,GACAA,EAAgBqN,SAAStN,QAE7BM,KAAKwM,OAAOU,OAAOxN,EAAO,GAG9BM,KAAK6E,mBAAmBpF,GACnBiE,QACG+B,KAAU9F,GACFA,EAASmF,SAAWvF,cACb,EAAC,GAEDS,KAAK6E,mBAAmBpF,EAAcE,EAAS+E,SAAW,IAAIhB,QACjEC,KAAI/D,GAAKA,EAAEkF,SAAWvF,kBAIlC,OAAUI,GAAYA,EAAUK,KAAKmB,YAAY4T,MAAMW,SAAS1V,KAAKsB,IAAI+J,QAAU,KAEtF7J,UACG,KACI,MAAM7B,EAAkBK,KAAKK,WAAWW,IAAI,UACxCrB,GACAA,EAAgBqN,SAAStN,GAE7BM,KAAKyB,oBAAoBC,SAAQ,OAAE,gCAAiC,CAChEC,OAAQ,gBAGhBhC,IACIK,KAAKyB,oBAAoBG,OAAM,OAAE,8BAA+B,CAC5DD,OAAQ,iBAMpBkD,mBAAmBpF,EAAsBC,GAC7C,OAAOM,KAAK+E,aACPC,OAAO,CACJC,SAAOC,KAAE,sCACTE,KAAM1F,EACN2F,QAAS,CACL,CAAEC,KAAM,YAAaC,SAAOL,KAAE,kBAC9B,CAAEI,KAAM,SAAUC,OAAO,OAAE,iBAAkBC,aAAa,MAGjE9B,QACG+B,KAAU9F,GACNA,EAASK,KAAKmB,YAAY4T,MAAMe,kBAAkB,CAACrW,KAAiBC,GAAWgG,MAEnF,OAAI/F,GAAUA,EAAOmW,kBAAkB,KAOzCjU,cAAcpC,EAAgCC,SACpD,MAAME,GAAqB,SAAgBH,EAAOC,GAUlD,GARAM,KAAKK,WAAW2N,WAAW,CACvB+G,MAAO,CACHzI,KAAM7M,EAAM6M,KACZtB,SAAUvL,EAAMwO,UAChB3N,KAA8B,QAAxBX,EAAkB,MAAlBC,OAAkB,EAAlBA,EAAoBU,YAAI,QAAI,MAItCN,KAAKE,aAAa4B,OAAQ,CACA9B,KAAKK,WAAWW,IAAI,CAAC,QAAS,iBACxDhB,KAAK+B,yBACD/B,KAAKE,aACLF,KAAKK,WAAWW,IAAI,CAAC,QAAS,iBAC9BvB,EACAG,GAIR,MAAMC,EAAyBG,KAAKK,WAAWW,IAAI,UACnDhB,KAAKwM,OAAS,IAAI/M,EAAM+M,QACxB/M,EAAM+M,OAAO2B,QAAQrO,kBACjB,MAAM6I,GAAmB,SAAgB7I,EAAOJ,GAC1CkJ,EAAQ,CACVtH,GAAIxB,EAAMwB,GACVgL,KAAMxM,EAAMwM,KACZhM,KAAMqI,EAAmBA,EAAiBrI,KAAO,IAErD,IAAIuI,EAAehJ,EAAuBkW,SAAS1J,KAC/CvD,GAAWA,EAAQvH,MAAMD,KAAOxB,EAAMwB,IAU1C,GARIuH,GACsB,QAAtBvG,IAAatB,IAAI,aAAK,SAAEC,SAAS2H,EAAMtH,IACf,QAAxBoB,IAAa1B,IAAI,eAAO,SAAEC,SAAS2H,EAAM0D,MACjB,QAAxB/J,IAAavB,IAAI,eAAO,SAAEC,SAAS2H,EAAMtI,QAEzCuI,EAAe7I,KAAKQ,YAAYC,MAAMmI,GACtC/I,EAAuBiN,KAAKjE,IAE5B7I,KAAK8U,kBAAkBhT,OAAQ,CAC/B,IAAIgH,EAAyBD,EAAa7H,IAAI,CAAC,iBAM/C,GALK8H,IACDA,EAAyB,IAAI7I,KAAU,IACvC4I,EAAaqM,WAAW,eAAgBpM,IAGxCA,EACA,UAAWM,KAAYpJ,KAAK8U,kBAAmB,CAC3C,MAAMkB,EAAM5M,EAAS9I,KACf2V,GACgB,iBAAlB7M,EAAS9D,KACgD,QAAnDzC,EAAqC,QAArCJ,EAACkG,SAAoC,eAAEzI,oBAAY,eAAG8V,GACrDlW,EAAcI,aAAa8V,GAChCE,GAAUpN,EAAuB9H,IAAIgV,GACvCE,GACAA,GAAQjV,SAASgV,IAEjBnN,EAAuBoM,WAAWc,EAAK,IAAI/V,KAAYgW,SAYvEb,gBACJ3V,EACAC,EACAC,GAEA,MAAMC,KAAQL,OAA0B,CACpC6O,aAAc3O,EACd4O,cAAe3O,EAAe6B,MAC9B+M,kBAAmBtO,KAAKE,aACxBqO,eACAC,mBAAoB,CAChBD,eACAjO,KAAMb,EAAMa,MAAQ,MAG5B,SAAM2N,WAAavO,EAAe6B,MAAMyJ,QACjCpL,EAOH4V,sBACJ/V,EACAC,EACAC,GAEA,OAAOD,EAAgBqW,SAClB9S,OAAOrD,IAAMA,EAAE2B,MAAMD,IACrBsB,IAAIhD,GAAKA,EAAE2B,OACXqB,IAAIhD,MACDL,OAA0B,CACtB6O,aAAYzN,+BAAOf,GAAK,CAAEuW,aAAc,KACxC9H,cAAezO,EACf0O,kBAAmBtO,KAAK8U,kBACxBvG,eACAC,mBAAoB,CAChBD,eACAjO,KAAM,OAIjBsC,IAAIhD,GAASe,eACVyV,QAAS3W,EAAM6B,IACZ1B,IAQP+V,sBACJlW,EACAC,EACAC,GAEA,MAAMC,EAAcH,EAAM+M,OAAOvJ,OAAO,CAACnD,EAAGwC,KACxC,MAAMI,EAAUhD,EAAgBsB,IAAIsB,EAAE+T,YACtC,OAAO3T,GAAWA,EAAQyK,OAASzK,EAAQnB,MAAMD,KAE/CzB,EAAmBH,EAAgBqW,SACpC9S,OAAOnD,GAAKA,EAAEqN,OAASrN,EAAEyB,MAAMD,IAC/BsB,IAAI9C,GAAKA,EAAEyB,OAEhB,GAAI3B,EAAYkC,SAAWjC,EAAiBiC,OACxC,MAAM,IAAIoO,SAAMhL,KAAE,+CAEtB,OAAOtF,EACFgD,IAAI,CAAC9C,EAAOwC,OACF/C,OAA0B,CAC7B6O,aAActO,EACduO,cAAexO,EAAiByC,GAChCgM,kBAAmBtO,KAAK8U,kBACxBvG,eACAC,mBAAoB,CAChBD,eACAjO,KAAM,OAIjB2C,OAAOqT,8DAnZPC,IAAoBlX,gIAApBkX,GAAoBtU,6gEDjCjC5C,0BAAgB,iBAERA,8CACAA,mCAIIA,8CAAsBK,sEACzBL,UAGLA,wBACIA,kCACAA,8CAQAA,4CAUJA,UAGJA,sEAhCyBA,8CAEbA,+CAA2B,2DAA3BA,CAA2B,mDAW1BA,6CAAsB,cAmBUA,+aEbrCA,eAKIA,sBACAA,8BACJA,eAJIA,gCAGAA,wFA6BAA,4DAEIA,sBAAoB,eAApBA,CAAoB,kDASpBA,SACIA,sBACAA,SACJA,8CADIA,8EAGAA,gEAVRA,qBAGIA,sEAASmX,wBAETnX,kCAIAA,4CAGJA,0DAPmBA,iEAA2D,sCAW1EA,SAAqDA,8BAEnDA,eAFmDA,oEAG/BA,2MA5B9BA,iBAAgEA,SAAgBA,QAChFA,iBAAgEA,SAAgBA,QAChFA,iBACIA,2DAMAA,4BAaJA,QACAA,iBAAgE,cAExDA,mCAGAA,6CACJA,UAEJA,kBACIA,0DAKJA,QACAA,kBAAiE,kBAAjEA,CAAiE,gBAGrDA,gCACAA,wBACJA,QACAA,iCAA8C,gBAItCA,sDAASA,EAATwG,MAAS4Q,8CAITpX,wBACAA,gCACJA,2DAtDkBA,6BAAkCA,uBAClCA,sCAAkCA,uBAClCA,sCAEJA,yEAOjBA,sDAYqBA,sCAEPA,oCAAwB,cAMhBA,sCAGvBA,mDAAmC,4BAIZA,sCAGnBA,sDAQIA,sDAIAA,iHCjFjB,iBACKE,MAURC,YACYC,EACAC,EACAC,EACAC,EACRC,EACAC,GAEAC,MAAMF,EAAQC,GAPNE,mBACAA,oBACAA,2BACAA,2BAXZA,uBAAoB,IAAIC,KAAY,IAG3BD,kBAAe,EACxBA,kBAAyC,GAYrCD,MAAMoC,WACF,IAAIG,IAAgBtC,KAAKmB,YAAY4T,MAAM2B,aAAapU,GAAM6Q,yBAC9D7Q,GAAQA,EAAKqU,OACb,CAACrU,EAAMI,KAAU,CACbI,QAAS,CACLC,OACAC,OACAC,OAAQ,CACJ3C,KAAM,CACF4C,SAAUlD,KAAK4H,kBAAkBrG,QAGzC4B,KAAM,CACFC,UAAWwT,gBAK3B5W,KAAK8Q,iBAAmB,IAAIvR,MAAiB,CACzCwT,aAAa,EACbC,cAAe,CAAC1Q,EAAGI,IAAMJ,EAAEhB,KAAOoB,EAAEpB,GACpCwR,cAAc,IAItB1S,WACIL,MAAMK,WACNJ,KAAKwT,oBAAsBxT,KAAKyT,oBAAoBC,wBACpD1T,KAAK2T,iBAAmB3T,KAAKmB,YAAYiQ,OACpCwC,UACAzP,UAAU,EAAGyP,aAAcnU,EAAQoU,iBACnCnQ,MAAK,OAAI,IAAM1D,KAAKgE,YACzBhE,KAAK4H,kBAAkBC,aAClBnE,QACGyE,MAAO1I,GAAS,GAAKA,EAAMqC,QAA2B,IAAjBrC,EAAMqC,WAC3C8J,KAAa,QACbiL,KAAU7W,KAAK+D,WAElBvC,UAAU,IAAMxB,KAAKgE,WAG9BwS,mBAAmB/W,GACXO,KAAK8W,aAAarX,EAAM6B,MAAQ7B,EAAM+M,OAAO1K,OAC7C9B,KAAK8W,aAAarX,EAAM6B,IAAMtB,KAAK+W,aAEnC/W,KAAK8W,aAAarX,EAAM6B,IAAM7B,EAAM+M,OAAO1K,OAInD2U,YAAYhX,GACRO,KAAK6E,mBAAmBpF,GACnBiE,MACG,OAAUhE,GACFA,EAASoF,SAAWvF,cACb,EAAC,GAEDS,KAAK6E,mBAAmBpF,EAAcC,EAASgF,SAAW,IAAIhB,QACjEC,KAAIhE,GAAKA,EAAEmF,SAAWvF,oBAKlCkG,KAAU,IAAMzF,KAAKmB,YAAY4T,MAAMO,eAAejK,UAEzD7J,UACG,KACIxB,KAAKyB,oBAAoBC,SAAQ,OAAE,gCAAiC,CAChEC,OAAQ,eAEZ3B,KAAKgE,WAETtE,IACIM,KAAKyB,oBAAoBG,OAAM,OAAE,8BAA+B,CAC5DD,OAAQ,iBAM5B0S,YAAY5U,GACRO,KAAKmB,YAAYiQ,OAAOkD,mBAAmB7U,GAAM+B,YAG7CqD,mBAAmBpF,EAAiBC,GACxC,OAAOM,KAAK+E,aACPC,OAAO,CACJC,SAAOC,KAAE,gCACTE,KAAM1F,EACN2F,QAAS,CACL,CAAEC,KAAM,YAAaC,SAAOL,KAAE,kBAC9B,CACII,KAAM,SACNC,MAAO7F,KAAUwF,KAAE,0BAAyBA,KAAE,iBAC9CM,aAAa,MAIxB9B,QACG+B,KAAU9F,GAAQA,EAAMK,KAAKmB,YAAY4T,MAAM0B,YAAYhX,IAAWC,GAAWgG,MACjF,OAAI/F,GAAOA,EAAI8W,sDAvHlBO,IAAkB3X,uGAAlB2X,GAAkB/U,6tCDzB/B5C,0BAAgB,gBAAhBA,CAAgB,WAGJA,wCAOAA,eAAK,6BAIGA,8CAAsBK,qDACzBL,cAIbA,wBACIA,mCACAA,uBAQJA,UAGJA,6BAKIA,sCAAcK,oBAAdL,CAAoC,wCACdK,+FAGtBL,mCAKAA,0BAAeA,gCAA+BA,QAC9CA,0BAAeA,gCAA+BA,QAC9CA,4BAA+BA,gCAAkCA,QACjEA,0BAAeA,gCAAsCA,QACrDA,0BAA+B,oBAE/BA,iCA4DJA,eA1GgBA,kDAAiC,oDAM7BA,2EAAsD,sDAW7DA,gDAUTA,8CAAwB,4CAAxBA,CAAwB,wCAAxBA,CAAwB,0CAAxBA,CAAwB,uCAUpBA,kCAAsB,uCAGXA,2CACAA,2CACAA,4BAAgBA,8CAChBA,odEjDSA,oHAOxBA,oBAAkCA,iDAAS4X,WAAU5X,8BAAiCA,QACtFA,oBAEIA,iDAAS6X,iBAIT7X,8BACJA,gCARqDA,2CAIjDA,uDAGAA,yDCMD,SAOHG,YAAoBC,yBAJpBO,oBAA+B,GAM/BmX,kBACIC,WAAW,IAAMpX,KAAKqX,SAASC,QAAS,GAG5CJ,eACIlX,KAAKuX,YAAYvX,KAAKwX,gBAG1BP,SACIjX,KAAKuX,sDAlBAE,IAAyBpY,wCAAzBoY,GAAyBxV,4EACvB1C,MAA2B,sRDrB1CF,gCAEAA,sCACIA,qEACHA,QAEDA,kLELIA,SAAkEA,8BAEhEA,eAFgEA,wFAGnCA,qHAH/BA,kCAGAA,6EAHeA,qCAA4B,iFAsCvBA,iMAGAA,sHAWAA,yMAE6BA,yCAPzCA,cAAiD,QACzCA,SAAcA,QAClBA,cAAIA,mCAA8DA,QAClEA,cACIA,gCAGAA,4CACJA,yDAPIA,uBACAA,6FAEaA,yCAAwB,qFAc7CA,yMAGAA,qIANRA,qBAAkCA,iDAAS4X,WAAU5X,8BAAiCA,QACtFA,qBAAsBA,iDAASqY,WAC3BrY,gCAGAA,2CAGJA,2CARqDA,2CACZA,8CACxBA,yCAAwB,eC5CtC,QAkBHG,YAAoBC,EAAkCC,GAAlCM,mBAAkCA,2BAZtDA,wBAAqB,IAAIC,KAAY,GACrCD,8BAA2B,IAAIC,KAO3B0X,2BACA,OAAiC,MAA1B3X,KAAK4X,kBAKhBxX,WACI,MAAMX,EAAmBO,KAAKmB,YAAYiQ,OACrCC,aACAlI,UAAU,EAAGkI,gBAAiB1R,EAAWkY,iBACxCnY,EAAeM,KAAKmB,YAAY2W,SAASC,cAAc5O,UAAUxJ,GAAQA,EAAKqY,aAEpF5K,KAAc3N,EAAkBC,GAAc8B,UAAU,EAAE7B,EAAiBC,MAEvEI,KAAKiY,eAAiBrY,EAASyM,KAAKxM,GAAKA,EAAEyB,KAAO3B,GAClDK,KAAKkY,kBAAoBtY,IAG7BI,KAAKmY,yBAAyBtQ,aAAarG,UAAU7B,IACjDK,KAAKoY,cAAczY,KAGvBK,KAAKqY,kBAAmB,UACpBC,MAAKtY,KAAKuY,eAAe,KACzBvY,KAAKwY,mBAAmB3Q,aAAanE,MAAK,QAAU,KACtDA,QACEC,KAAI,EAAEhE,EAAUC,KACLD,EAASiD,IAAI/C,IAAM,CACtByB,GAAIzB,EAAEyB,GACNhB,KAAMT,EAAES,KACRmY,MAAO5Y,EAAE4Y,MACTC,aAAc7Y,EAAE4Y,OAAS7Y,OAMzCwY,cAAc3Y,GACVO,KAAK2Y,gBAAkB3Y,KAAKkY,kBAAkB7L,KAAK3M,GAAKA,EAAE4B,KAAO7B,EAAW,IAGhFiY,SACI,MAAMjY,EAAkBO,KAAK2Y,gBACzBlZ,IACKO,KAAK2X,qBAcC3X,KAAK4X,mBACZ5X,KAAKmB,YAAYC,QACZwX,wBAAwB,CACrBC,UAAWpZ,EAAgB6B,GAC3BsW,kBAAmB5X,KAAK4X,kBACxBkB,aAAc9Y,KAAKwY,mBAAmBjX,QAEzCC,UAAU,KACPxB,KAAKyB,oBAAoBC,SAAQ,OAAE,6CAA8C,CAC7EqX,QAAStZ,EAAgB6M,KAEzB3H,MAAO3E,KAAK4X,kBAAmB9V,SAEnC9B,KAAKuX,aAAY,KA1BzBvX,KAAKmB,YAAYC,QACZ4X,wBAAwB,CACrBH,UAAWpZ,EAAgB6B,GAC3B2X,WAAYjZ,KAAKiZ,WACjBH,aAAc9Y,KAAKwY,mBAAmBjX,QAEzCC,UAAU,KACPxB,KAAKyB,oBAAoBC,SAAQ,OAAE,6CAA8C,CAC7EqX,QAAStZ,EAAgB6M,KACzB3H,MAAO3E,KAAKiZ,WAAWnX,SAE3B9B,KAAKuX,aAAY,MAqBrCN,SACIjX,KAAKuX,cAGKgB,eAAe9Y,kDACzB,MAAMC,EAAqC,GAE3C,QAASC,EAAI,EAAGA,EAAIK,KAAKiZ,WAAWnX,QAAUpC,EAASoC,OAASrC,EAAME,IAAK,CACvE,MAAMC,QAAwBI,KAAKmB,YAAYC,QAC1C8X,WAAWlZ,KAAKiZ,WAAWtZ,GAAI,CAAEqD,KAAMhD,KAAK2X,0BAAuB,EAAYlY,IAC/E0J,UAAU,EAAG/H,cACQvB,EAAUA,EAAQsZ,YAAY/U,MAAQ,IACvCnB,OAAOX,IAAI,MACxB,YAAKqV,uBAA6C,QAAtBjV,OAAKkV,yBAAiB,eAAEzI,SAAS7M,EAAEhB,QAGtE8X,YACL1Z,EAASoN,QAASlN,GAAmB,IAEzC,OAAOF,EAASyG,MAAM,EAAG1G,4CA9GpB4Z,GAAsCha,oDAAtCga,EAAsCpX,ioBDrBnD5C,gCAOAA,iBAAkB,wBAAlBA,CAAkB,WAEHA,8BAAkCA,QACzCA,4CAOJA,QACAA,iBACAA,+BAAqB,WACVA,gCAAmDA,QAC1DA,oBACJA,UAGJA,kBAAmC,cACEA,gCAAiDA,QAClFA,oBAAqB,WAArBA,CAAqB,QAArBA,CAAqB,SAGLA,gCAA+BA,QACnCA,eACIA,qFAIJA,QACAA,eACIA,iCAGAA,4CAGJA,YAGRA,kBACIA,4CAUJA,YAIRA,0DArDeA,6CAGHA,8BAAkB,2BAAlBA,CAAkB,wCAAlBA,CAAkB,0CAQfA,+DAC2CA,mDAKrBA,6DAIjBA,2CAEAA,yJAMaA,yCAAwB,cAUzBA,ubE3CzB,YAAqBwP,EAAmCpP,EAAgBC,GAC3E,IAAKmP,EACD,MAAO,GAEX,MAAMlP,EAAYkP,EAAOyK,YAAY7Z,GACrC,IAAkB,IAAdE,EACA,OAAOkP,EAIX,OAFaA,EAAO0K,OAAO,EAAG5Z,GACjBkP,EAAO0K,OAAO5Z,GAAW6Z,QAAQ/Z,EAAQC,GCkBnD,QACHF,YAAoBC,sBAEpBga,mBACI,OAAOzZ,KAAKmB,YAAY2W,SACnB2B,mBACAtQ,UAAU1J,GAAQA,EAAKia,eACvBhW,QAAK6N,MAAY,IAG1BoI,0BACIla,EACAC,EACAC,GAEA,MAAMC,EAAiBI,KAAKmB,YAAYC,QAAQwY,cAAcna,GACxDI,EAAuBH,EAAqBma,OAAO5W,OAAOX,GAAK,EAAIA,EAAEkK,OAAO1K,QAC5EhC,EAAsBE,KAAK8Z,0BAA0Bja,EAAsBF,GAEjF,OAAO,OAASC,EAAgBE,GAAqB4D,QACjDqW,KAAS,GAAIH,iBAAiBlX,MACGA,EAAaZ,UACpC+T,KACInT,EAAaE,IAAIH,GACNzC,KAAKmB,YAAYC,QAAQ4Y,wBAAwB,CACpDC,UAAW3X,EAAchB,GACzB4Y,cAAezX,EAAYnB,UAIvCiI,MAAG,KACmB7F,MACxB,OAAI,KACO,CAAEkW,gBAAeO,qBAIpC,OAAS,EAAGP,gBAAeO,mBACvB,MAAM5X,EAAW7C,EAAqB0a,SAASxX,IAAIC,IAC/C,MAAM8F,EAAYjG,EAAaZ,OACzBe,EAAEwX,aAAazX,IAAI,CAACgG,EAAYC,KAC5B,MAAMC,EAASpG,EAAamG,GAAO/F,QAAQuJ,KAAKjD,GAAKA,EAAE9I,OAASsI,GAChE,IAAKE,EACD,MAAM,IAAIoH,MACN,4CAA4CtH,4BAGpD,OAAOE,EAAOxH,KAElB,GACN,sCACOuB,GAAC,CACJyX,gBAGF7X,EAAUC,EAAaE,IAAIC,GAAMA,EAAGC,SAASpC,OAAO,CAACmC,EAAM8F,IAAM,IAAI9F,KAAS8F,GAAI,IACxF,OAAO3I,KAAKua,sBAAsBjY,EAAeC,EAAUE,EAAS9C,MAKhFma,0BAA0Bra,EAAmDC,GACzE,OAAOD,EAAOqC,UACR+T,KACIpW,EAAOmD,IAAIjD,GACAK,KAAKmB,YAAYC,QACnB0Y,0BAA0B,CACvBxN,MAAM,QAAgB3M,EAAEW,KAAM,KAC9B6V,aAAc,CAAC,CAAE5H,eAAcjO,KAAMX,EAAEW,OACvCwC,QAASnD,EAAE6M,OAAO5J,IAAIhD,IAAM,CACxB0M,MAAM,QAAgB1M,EAAG,KACzBuW,aAAc,CAAC,CAAE5H,eAAcjO,KAAMV,SAG5C8D,QAAKC,KAAI/D,GAAQA,EAAK4a,gCAGnCjR,MAAG,IAGbgR,sBACI9a,EACAC,EACAC,EACAC,GAEA,MAAMC,EAAwCH,EAAYkD,IAAI9C,IAC1D,MAAMwC,EAAO3C,EAAQmC,OACf,GAAGrC,EAAQa,QAAQR,EAAEwa,UAChB1X,IAAIF,GAAM/C,EAAQ0M,KAAK9J,GAAKA,EAAEjB,KAAOoB,IACrCO,OAAOqT,sBACP1T,IAAIF,GAAKA,EAAEpC,MACXkQ,KAAK,OACV/Q,EAAQa,KACd,MAAO,CACH2Z,UAAWxa,EAAQ6B,GACnBmX,MAAO3Y,EAAE2Y,MACTgC,IAAK3a,EAAE2a,IACPC,YAAa5a,EAAE6a,MACfxE,aAAc,CACV,CACI5H,eACAjO,SAGRga,UAAWxa,EAAEwa,aAGrB,OAAOta,KAAKmB,YAAYC,QAAQmZ,sBAAsB1a,GAAU6D,MAC5D,OAAI,EAAG6W,4BAA6B,CAChCA,wBACAN,UAAWxa,EAAQ6B,OAK/BsZ,cAAcnb,GAOV,MAAQ2B,UAASmN,eAAcsM,aAAYC,eAAcC,iBAAkBtb,EACrE6C,EAA6F,GAC7FI,EAAsB5C,GAAiB,GAQ7C,OANkBF,EACZI,KAAKmB,YAAYC,QACZ4Z,mBAAmB,GAAItb,EAAQ4B,IAC/B6H,UAAU,EAAGG,qBAAsB7G,EAAgB2B,UACxDmF,MAAG,KAEQ7F,MACb,OAASjB,gBACL,GAAI5C,EAAc,CACdyC,EAAiBwK,KAAK9M,KAAKmB,YAAYC,QAAQwZ,cAAc/a,IAC7D,MAAMiJ,EAA6D,QAA5CH,EAAsC,QAAtC9F,YAAgBnD,EAASC,UAAa,eAAEW,YAAI,QAAI,GACjE8I,EAA4D,QAA3CR,YAAgB/I,EAAcF,UAAa,eAAEW,KACpE,GAAI8I,GAAkBN,IAAmBM,GAAkBxJ,EACvD,UAAWoW,KAAWvT,EAAU,CAC5B,MAAMwT,IAA2D,QAAtCpN,YAAgBmN,EAASrW,UAAa,eAAEW,OAAQ,GAC3E,IAAI4V,GACJ,MAAM+E,GAAuBvY,EAAoB2J,KAAK6O,IAAKA,GAAE5Z,KAAO0U,EAAQ1U,IACxE2Z,GACA/E,GAAe+E,IAEf/E,GAAe,CACX5U,GAAI0U,EAAQ1U,GACZ6U,aAAc,CAAC,CAAE5H,eAAcjO,KAAM2V,MAEzCvT,EAAoBoK,KAAKoJ,KAE7B,MAAMiF,IAAqB,SAAgBjF,GAAcvW,GACrDwb,KACIA,GAAmB7a,KACnB6a,GAAmB7a,KAAO8a,GACtBD,GAAmB7a,KACnBwI,EACAM,GAMJ+R,GAAmB7a,KAAO,CACtB8I,KACG4M,EAAQlT,QAAQF,IAAIsY,IAAKA,GAAE5a,OAChCkQ,KAAK,OAM3B,OAAI9N,EAAoBZ,QACpBQ,EAAiBwK,KACb9M,KAAKmB,YAAYC,QAAQia,sBAAsB3Y,OAGhDmT,KAASvT,MAK5BgZ,oBACI7b,EACAC,EACAC,GAQA,OANkBF,EAAMob,WAClB7a,KAAKmB,YAAYC,QACZ4Z,mBAAmB,GAAItb,EAAQ4B,IAC/B6H,UAAU,EAAGG,qBAAsBzJ,EAAgBuE,UACxDmF,MAAG,KAEQ7F,MACb,OAAS7D,cACL,IAAI0C,KAA8CgH,MAAG,IACrD,GAAI9J,EAAMob,WAAY,CAElB,IAAIpY,EACJ,MAAMI,EAAoD,QAApC/C,YAAgBL,EAAOE,UAAa,eAAEW,KACvDuC,IACDN,KAA6BgH,MAAG,KAEpC,MAAMZ,EAAgD,GACtD,UAAWC,KAAW/I,EAClB,GAAI+I,EAAQ9F,QAAQF,IAAIiG,GAAKA,EAAEvH,IAAI6N,SAAS1P,EAAM6B,IAAK,CAC9CmB,IACDA,EAGC,QAHeH,YACZsG,EAAQ9F,QAAQuJ,KAAKvD,GAAKA,EAAExH,KAAO7B,EAAM6B,IACzC3B,UACH,eAAEW,MAEP,MAAMuI,GAAoD,QAAtCnG,YAAgBkG,EAASjJ,UAAa,eAAEW,OAAQ,GAChEmC,GAAiBI,GAAiBgG,EAAYsG,SAAS1M,IACvDkG,EAAiBmE,KAAK,CAClBxL,GAAIsH,EAAQtH,GACZ6U,aAAc,CACV,CACI5H,eACAjO,KAAM8a,GAAYvS,EAAapG,EAAeI,OAOlE8F,EAAiB7G,SACjBS,EACIvC,KAAKmB,YAAYC,QAAQia,sBAAsB1S,IAG3D,OAAO3I,KAAKmB,YAAYC,QACnBka,oBAAoB7b,GACpBiE,MAAK,OAAS,IAAMnB,OAKrCgZ,qBAAqB9b,EAAYC,GAC7B,OAAOM,KAAKmB,YAAYC,QAAQma,qBAAqB9b,GAAIiE,MACrD,OAAU/D,GACFA,EAAO4b,qBAAqBzW,SAAWvF,cAChCS,KAAKmB,YAAYC,QAAQ8X,WAAWxZ,GAAW2L,QClRnE,iBACP,SAAyB,QAAUwD,WACnClP,kBACA,WAAe6b,KAAU/b,0BDiREgc,CAAW9b,EAAO4b,qBAAqB7W,kDAtPrDgX,GAAoBrc,yCAApBqc,EAAoB/K,QAApB+K,EAAoB,qBAFjB,6IE5BRrc,sBAMIA,+DAAaA,EAAbwG,OAAa8V,kBAEbtc,kBAAoC,eAK5BA,uDAAQA,EAARwG,OAAQ+V,mBAARvc,CAAgC,2CACD,IALnCA,UAQJA,mBAGIA,wDAASA,EAATwG,OAASgW,gBAAmDxc,SAAiBA,oEAjBjFA,oCAAyC,mBADzCA,sCAAyC,yBAMnCA,4CAIEA,iCAOJA,4CAC8BA,mCAA8BA,kDArBxEA,iBACIA,8BAsBJA,8BArB2BA,0CCiBxB,MAAMyc,GAA8C,CACvDC,QAAS9b,KACT+b,aAAa,SAAW,IAAMC,GAC9BC,OAAO,GAgBJ,QAqBH1c,YAAoBC,yBApBXO,eAAY,GAIXA,SAAM,IAAIX,MACVW,YAAS,IAAIX,MACbW,UAAO,IAAIX,MACZW,eAAW,EACpBA,WAAQ,GACRA,iBAAa,EACbA,mBAAe,EAEfA,mBAAe,EAIXqa,2BACA,OAAqC,QAA9B3a,EAAc,QAAdD,OAAK0c,iBAAS,QAAInc,KAAK8C,eAAO,QAAI,GAK7CsZ,iBAAiB3c,GACbO,KAAKqc,WAAa5c,EAGtB6c,kBAAkB7c,GACdO,KAAKuc,UAAY9c,EAGrB+c,iBAAiB/c,GACbO,KAAKyc,SAAWhd,EAChBO,KAAK0G,eAAeC,eAGxB+V,WAAWjd,GACPO,KAAKmc,UAAY1c,GAAO,GAG5B6X,QACItX,KAAK2c,SAASC,cAActF,QAGhCuE,SAASpc,EAAeC,SACpB,MAAME,EAAcI,KAAKqa,aAAa5a,GACtC,IAAKG,EAAYid,SAAWjd,EAAY0B,GAAI,CACxC5B,EAAMod,cAAe,EACrB9c,KAAK+c,aAAetd,EACpB,MAAMI,EAAkC,QAA1BF,OAAKqd,WAAWhc,IAAIvB,UAAM,eAAEmd,cAC1CxF,WAAW,IAAW,MAALvX,OAAK,EAALA,EAAOyX,UAIhCsE,aAAanc,EAAeC,GACxB,MAAMC,EAAcK,KAAKqa,aAAa5a,GAChCG,EAAWF,EAAMud,OAA4B1b,MAC/C5B,IACIC,IACAD,EAAYW,KAAOV,EACnBI,KAAKkd,KAAKjW,KAAK,CAAEkJ,QAAOgN,OAAQxd,KAEpCK,KAAK+c,cAAe,GAI5BpB,aAAalc,SACJA,EAAOod,SACJ7c,KAAKmc,WACLnc,KAAKmc,UAA0B,QAAdzc,OAAKyc,iBAAS,eAAElZ,OAAOtD,GAAKA,EAAEW,OAASb,EAAOa,MAC/DN,KAAKqc,WAAWrc,KAAKmc,YAErBnc,KAAKod,OAAOnW,KAAKxH,IAK7B4d,UAAU5d,GACN,OAAQA,EAAM6d,SACL,QACA,QACDtd,KAAKud,iBACL9d,EAAM+d,iBACN,UACC,YACGxd,KAAKyd,cACLzd,KAAK0d,mBACL1d,KAAKyd,cAAe,GACE,KAAfzd,KAAK2d,QACZ3d,KAAKyd,cAAe,GAExB,cAEAzd,KAAKyd,cAAe,GAIhCG,aACI5d,KAAK6d,YAAa,EAClB7d,KAAKud,iBAGDA,iBACJ,MAAM9d,EAAUO,KAAK8d,sBAAsB9d,KAAK2d,OAAO1a,OAAOvD,UAG1D,MAAME,EAAuB,QAAZD,OAAKmD,eAAO,QAAI9C,KAAKmc,UACtC,QAAgB,MAARvc,OAAQ,EAARA,EAAUyM,KAAKxM,IAAM,MAADA,OAAC,EAADA,EAAGS,QAASZ,EAAOY,SAEnD,IAAKN,KAAKmc,WAAanc,KAAK8C,QACxB,UAAWpD,KAAUD,EACjBO,KAAK+d,IAAI9W,KAAKvH,QAGlBM,KAAKmc,WAAY,OAAO,IAAInc,KAAKmc,aAAc1c,IAC/CO,KAAKqc,WAAWrc,KAAKmc,WAEzBnc,KAAK2d,MAAQ,GAGTG,sBAAsBre,GAC1B,OAAOA,EACFuS,MAAM,SACNpP,IAAIlD,GAAKA,EAAEse,QACX/a,OAAOvD,GAAW,KAANA,GACZkD,IAAIlD,IAAM,CAAEY,KAAMZ,EAAGmd,QAAQ,KAG9Ba,mBACJ,GAAI1d,KAAKqa,aAAavY,OAAQ,CAC1B,MAAMrC,EAASO,KAAKqa,aAAara,KAAKqa,aAAavY,OAAS,GAC5D9B,KAAK2b,aAAalc,2CAnIjBwc,GAAyB5c,uCAAzB4c,EAAyBha,6FAGK5C,oOAL5B,CAACyc,MAAkCmC,4bDrClD5e,iBAAsDA,kDAASiY,UAC3DjY,wBAwBAA,wBAEIA,iCAASK,gBAATL,CAA2B,wCACL,GADtBA,CAA2B,yBAEnBK,gBAFRL,CAA2B,+CAK9BA,gBAhCsBA,4BACHA,+CA6BhBA,kCAAmB,02CE9B3BA,iBAA8D,UAA9DA,CAA8D,WAE/CA,8BAAkCA,QACzCA,sBAIIA,qEAAwB,8DAGPA,EAHOwG,MAGPqY,mBAPrB7e,UAUJA,kBAAoB,WACTA,+BAAyCA,QAChDA,yCAEIA,uEAA0B,mDACT8e,oBADjB9e,CAA0B,0CAElB8e,qBAGX9e,UAELA,mBAA0B,gBAIlBA,2DAASA,EAATwG,MAAS8V,6CAETtc,wBACJA,wCA7BOA,4CAKHA,iCAOGA,oDAGHA,mCAA0B,mBAA1BA,CAA0B,wBAU1BA,qFAgBIA,cAAgCA,8BAAiCA,eAAjCA,mEAChCA,cAAgCA,8BAAmCA,eAAnCA,uFAUpCA,cAAgC,cAGxBA,mDAAU+e,gBAAV/e,CAAyB,kHAF7BA,sDAGIA,uFAIRA,cACIA,SACJA,wCADIA,qFAbRA,cAIIA,uBAQAA,uBAGAA,cAAI,wBAAJA,CAAI,cAKQA,kDAAU+e,gBAAV/e,CAAyB,2HAH7BA,YASRA,cAAI,wBAAJA,CAAI,2BAIQA,8GAAiD,mDAChC+e,iBAEpB/e,YAGTA,eAAI,yBAAJA,CAAI,eAKQA,8GAAiD,4CACvC+e,iBAJd/e,oDApCRA,qDAEKA,2CAQAA,2CASOA,wDAA+C,wCAS/CA,0DAAiD,+BAWjDA,2DCrFxB,MAAMgf,GAAuB,sBAkBtB,SAOH7e,YAAoBC,sBANVO,oBAAiB,IAAIX,MAE/BW,kBAA0F,GAG1FA,uBAA2D,GAG3DI,WACIJ,KAAKmB,YAAY2W,SAASwG,mBAAmBjT,QAAQ7J,UAAU/B,IAC3DO,KAAKue,aAAe9e,EAAK+e,cAAcD,eAG3Cve,KAAKme,mBAGTM,YACIze,KAAKma,aAAarN,KAAK,CAAExM,KAAM,GAAIkM,OAAQ,KAC3C,MAAM/M,EAAQO,KAAKma,aAAarY,OAAS,EACzCsV,WAAW,WACP,MAAMzX,EAAuC,QAA/BD,OAAKgf,gBAAgB1d,IAAIvB,UAAM,eAAEmd,cAC1C,MAALjd,KAAO2X,UAIfqE,aAAalc,GACTO,KAAKma,aAAena,KAAKma,aAAalX,OAAOvD,GAAKA,EAAEY,OAASb,GAC7DO,KAAKme,mBAGTA,mBAEI,MAAMze,EADmBM,KAAKma,aAAazZ,OAAO,CAACf,EAAKC,IAAUD,EAAMC,EAAM4M,OAAO1K,OAAQ,GAEvF9B,KAAKma,aAAavX,IAAIjD,GAAKA,EAAE6M,OAAO5J,IAAIhD,GAAKA,EAAEU,OAC/C,CAAC,CAAC+d,KACRre,KAAKoa,UAAW,6BAAwB1a,GAAQkD,IAAIjD,IAAW,CAAE2B,GAAI3B,EAAO6Q,KAAK,KAAMhE,YAEvFxM,KAAKoa,SAASjM,QAAQxO,IACbK,KAAK2e,kBAAkBhf,EAAQ2B,MAChCtB,KAAK2e,kBAAkBhf,EAAQ2B,IAAM,CACjC+Y,aAAc1a,EAAQ6M,OACtBoS,SAAS,EACTnG,MAAOzY,KAAK6e,gBAAgBlf,EAAQ2B,GAAI,QAAS,GACjDmZ,IAAKza,KAAK6e,gBAAgBlf,EAAQ2B,GAAI,MAAO,IAC7CqZ,MAAO3a,KAAK6e,gBAAgBlf,EAAQ2B,GAAI,QAAS,OAI7DtB,KAAKoe,eAGTvQ,UAAUpO,EAAeC,GACrB,OAAOA,EAAQ8M,OAAOgE,KAAK,KAG/B0N,YAAYze,EAAsBC,GAC9BD,EAAM+d,iBACN/d,EAAMqf,kBACNpf,EAA0B4X,QAG9B8G,eACI,MAAM3e,EAAmBO,KAAKoa,SAASxX,IAAIlD,GAAKM,KAAK2e,kBAAkBjf,EAAE4B,KAAK2B,OAAOvD,GAAKA,EAAEkf,SAC5F5e,KAAK+e,eAAe9X,KAAK,CACrB4S,OAAQ7Z,KAAKma,aAAavX,IAAIlD,IAAO,CAAEY,KAAMZ,EAAGY,KAAMkM,OAAQ9M,EAAG8M,OAAO5J,IAAIjD,GAAKA,EAAEW,SACnF8Z,SAAU3a,IAIVof,gBACJpf,EACAC,EACAC,GAEA,OAAOF,IAAc4e,GACfre,KAAK2e,kBAAkBN,IAAsB3e,GAC7CC,0CA7EDqf,IAAgC3f,wCAAhC2f,GAAgC/c,wFAEA5C,mhCD1B7CA,0BAkCAA,oBAA+CA,gCAASK,gBACpDL,sBACAA,8BACJA,QAEAA,iBAA8B,YAA9BA,CAA8B,UAA9BA,CAA8B,QAIdA,uBACAA,wBACAA,eAAIA,gCAA+BA,QACnCA,eAAIA,gCAAiCA,QACrCA,eAAIA,gCAAyCA,YAGrDA,0BAiDJA,iBAnGmBA,gCAoCnBA,yDAOiBA,2CACAA,2CACDA,2CACAA,6CACAA,qDAIYA,qCAAa,kkBE7CjCA,SACIA,cAAIA,SAAsBA,QAC9BA,kCADQA,kDAaQA,+DAEIA,+DAGAA,kBACIA,uBACJA,mCA2BhBA,SACIA,yCAKIA,SACJA,QACJA,4DAJQA,gEADAA,0CAGAA,0DAKAA,qGAGIA,qCAAqC,sEAIzCA,qGAGIA,qCAAqC,sEA3DrDA,WACIA,gBAAkF,UAAlFA,CAAkF,WAGtEA,wBAIAA,2CAKJA,YAGRA,gBAAkF,yBAE1EA,oEAOJA,UAEJA,iBAAkF,0BAE1EA,qEAOJA,UAEJA,mDASAA,kBAAwF,0BAEhFA,yCAOAA,yCAOJA,UAEJA,kBAAwF,0BAEhFA,+CAQJA,UAEJA,kBAAwF,yBAEhFA,+CAOJA,UAERA,sEAxFgEA,qBAC9BA,mDAIbA,6CAAgC,cAWnBA,mDAMlBA,4DAAgD,0CAK9BA,mDAMlBA,4DAAgD,0CAK3BA,2DASGA,mDAGvBA,kDAOAA,iDAQuBA,mDAQxBA,4DAIwBA,mDAOxBA,0FArFpBA,cACIA,mCAyFJA,4CAzFmBA,iDCKpB,SAWHG,YAAoBC,yBAJpBO,kBAAe,IAAI8O,IACV9O,sBAAmB,CAACT,oBAA0BA,qBAKvDa,WACIJ,KAAK0R,aAAe1R,KAAKif,UAAUpX,aAC9BnE,MACG,OAAIjE,GAASA,EAAMqC,WACnB8J,KAAa,IACb,UAEHpK,UAAU,KACPxB,KAAKkf,sBAGblf,KAAKkf,oBAGTre,cACQb,KAAK0R,cACL1R,KAAK0R,aAAaK,cAI1BlE,UAAUpO,EAAeC,GACrB,OAAwB,MAAnBA,EAAa4B,GACN5B,EAAa4B,GAEd7B,EAIf0f,iBAAiB1f,SACb,OAA2C,QAApCC,OAAK0f,oBAAoB3f,EAAQ6B,WAAG,eAAEkF,gBAAiB/G,EAAQ+G,cAG1E6Y,gBAAgB5f,GACZ,MAAMC,EAAQM,KAAKma,aAAa9N,KAAK1M,GAAKA,EAAE2B,KAAO7B,GACnD,OAAOC,GAASA,EAAMY,KAGlB4e,oBACJlf,KAAKsf,aAAapR,QAClB,UAAWzO,KAAgBO,KAAKif,UAAUlJ,SACtC/V,KAAKsf,aAAa1R,IAAInO,EAAa8B,MAAMD,GAAI7B,GAEjDO,KAAK0G,eAAeC,uCC5EAtH,6HDqBfkgB,IAA6BlgB,wCAA7BkgB,GAA6Btd,w0CDrB1C5C,mBAAqB,UAArBA,CAAqB,QAGTA,cACAA,cAAIA,8BAA+BA,QACnCA,cAAIA,8BAA+BA,QACnCA,mDAGAA,eAAIA,gCAAiCA,QACrCA,eAAIA,gCAAyCA,QAC7CA,eAAIA,gCAAkCA,YAG9CA,kBACIA,6CA2FJA,iBAtGYA,yCACAA,0CACkCA,2DAGlCA,6CACAA,qDACAA,8CAIgBA,qEAA0C,qmBEG1EA,mBAAqC,WAC1BA,8BAAwCA,QAC/CA,gEAMJA,8BAPWA,kDAGHA,8CAA6B,2CAA7BA,CAA6B,8EAOjCA,qBAAkCA,iDAAS4X,WAAU5X,8BAAiCA,QACtFA,qBAEIA,iDAASmgB,WAQTngB,8BACJA,sDAZqDA,2CAIjDA,qGAOAA,oECtBD,SANPG,cAUIQ,wBAAoB,EAOpBA,uBAAmB,EAGnBI,iBACI,MAAMV,EAAqBM,KAAKyf,cAActJ,aAAa9J,KACvD1M,GAAKA,EAAE4O,eAAiBvO,KAAK0f,gBAKjC,GAHA1f,KAAKM,KAA+B,QAAxBb,EAAkB,MAAlBC,OAAkB,EAAlBA,EAAoBY,YAAI,QAAI,GACxCN,KAAKsM,KAAOtM,KAAKyf,cAAcnT,KAC/BtM,KAAK2f,iBAAmB,IAAI1f,KAAU,IAClCD,KAAKE,aAAc,CACnB,MAAMP,EACDD,GAAuBA,EAA2BQ,cAAiB,GAExE,UAAWN,KAAYI,KAAKE,aAAc,CACtC,MAAML,EAAMD,EAASU,KACfR,EACgB,iBAAlBF,EAAS0F,KACH3F,EAAqBE,GACpBG,KAAKyf,cAAsBvf,aAAaL,GACnDG,KAAK2f,iBAAiBzK,WAAWtV,EAASU,KAAM,IAAIL,KAAYH,MAK5E0f,SACI,MAAM/f,KAASF,OAA0B,CACrC6O,aAAcpO,KAAKyf,cACnBlR,aAAcvO,KAAK0f,eACnBrR,cAAe,CACX/B,KAAMtM,KAAKsM,KACXhM,KAAMN,KAAKM,KACXJ,aAAcF,KAAK2f,iBAAiBpe,OAExC+M,kBAAmBtO,KAAKE,aACxBsO,mBAAoB,CAChBD,aAAcvO,KAAK0f,eACnBpf,KAAM,MAGdN,KAAKuX,YAAW5W,+BAAMlB,GAAM,CAAEob,WAAY7a,KAAK4f,qBAGnD3I,SACIjX,KAAKuX,cAGT1C,WAAWpV,IACFO,KAAK6f,mBAAqB7f,KAAKyf,cAAcnT,OAC9CtM,KAAKsM,MAAO,QAAgB7M,EAAW,8CA5DtCqgB,iCAAkC7d,oqBDlB/C5C,gCACAA,iDACIA,qBAIIA,oDAAkB,2BAETK,+BANbL,UASJA,iDACIA,qBAA2DA,oDAA3DA,UAEJA,gCAAsB,cACiBA,iEAAnCA,QACAA,kBAAOA,gCAA2DA,UAEtEA,6BAUAA,wCA3BgBA,yDAKRA,iCAKQA,iDAC+CA,iCAGxBA,8CAC5BA,uEAEDA,wQEjBVA,iBACIA,+CACJA,8BADIA,gLAEJA,iBACIA,0FAIJA,8BAJIA,oKCMG,SAYHG,YAAoBC,sBAHZO,kBAAe,IAAIkC,IAAwB,GAC3ClC,0BAAuB,IAAIkC,IAAwB,IAI3D9B,WACI,MAAMX,EAAYO,KAAKmB,YAAY2W,SAC9BiI,kBAAkB,IAAK,EAAG,eAC1B5b,UAAUxE,GAAQA,EAAKqgB,SAAS5b,OAC/B1E,EAAiBM,KAAKmB,YAAY2W,SACnCwG,iBAAiB,eACjBnL,yBACAhP,UAAUxE,GAAQA,EAAK6e,eAE5Bxe,KAAKigB,UAAW,OAAcvgB,EAAgBD,EAAWO,KAAKkgB,sBAAsBxc,QAChFC,KAAI,EAAEhE,EAASC,EAAUC,MACrB,MAAMC,EAAiBH,EAAQwgB,eAC/B,IAAKrgB,EACD,OAAO,EAEX,MAAMwC,EAAiB1C,EAASyM,KAC5B3J,GAAWA,EAAQ0d,KAAK9e,KAAOxB,EAAewB,IAAMoB,EAAQ2d,SAAS/e,KAAOzB,GAGhF,OAAKyC,EAGEA,EAAef,MAFX,KAMnBvB,KAAKsgB,eAAclT,KAAcpN,KAAKigB,SAAUjgB,KAAKugB,cAAc7c,MAC/D,OAAI,EAAE/D,EAASC,KACJ4gB,KAAKC,MAAM7gB,IAAU,IAAMD,GAAW,QAKzD+J,YAAYjK,GACJ,UAAWA,GACXO,KAAKugB,aAAa5W,KAAKlK,EAAQgZ,MAAM5O,cAErC,kBAAmBpK,GACnBO,KAAKkgB,qBAAqBvW,KAAKlK,EAAQihB,cAAc7W,sDApDpD8W,IAA2BthB,wCAA3BshB,GAA2B1e,mSDXxC5C,mBAAiCA,8BAAiCA,QAClEA,wBAGAA,gCAJiCA,2CAC3BA,0CAGAA,+PEiCcA,8BACIA,oBACAA,iBAAOA,8BAAkCA,iBAAlCA,uEA0BaA,qBAIIA,SACJA,kCAHIA,oBAEAA,0DATZA,gCAEC,WACUA,8BAAwCA,QAC/CA,qBACIA,4BAMJA,iCAROA,kDAGyBA,qEAQhCA,oBAAiCA,8BAE/BA,QACFA,kBACIA,SACJA,8CALiCA,kDAI7BA,2EAOJA,qGAGIA,qCAAqC,sEAIzCA,qGAGIA,qCAAqC,sEAcjDA,gCAA2D,WAElDA,8BACDA,oDAGJA,QACAA,qBAAkE,eAE1DA,8BACJA,QACAA,sBACIA,gCACJA,QACAA,sBACIA,gCACJA,mCAdCA,4DAEGA,wEAIIA,0CACJA,mEAEIA,2CACJA,qEAEIA,6CACJA,kGA6FZA,sBACIA,gEAOJA,8CALQA,8CAA6B,aAA7BA,CAA6B,8CAA7BA,CAA6B,qFAgBzCA,uBAIIA,+DAAaA,EAAbwG,OAAa+a,yCAGbvhB,mBAAgCA,SAAqCA,QACrEA,SACJA,+CAPIA,gDAA6C,YAA7CA,CAA6C,gDAKbA,6CAChCA,+GAVZA,eAAoC,YAE5BA,8CAUAA,gBACKA,8BAA2CA,6CAVzBA,yDASpBA,yCACEA,qGAMTA,mCAIIA,iFAAUA,EAAVwG,MAAUgb,oDACbxhB,+CAHGA,sBAAyB,qFAI7BA,qBAGIA,4EAASyhB,sBAETzhB,uBACAA,8BACJA,cADIA,8IASAA,uBAIIA,oGACyC0hB,0EAGzC1hB,gCACAA,uCACJA,0CAPIA,2EAKmBA,qCACnBA,qEAVRA,SACIA,+BAWJA,6CAVSA,6FAJjBA,kBAAmD,YAE3CA,kCAaAA,qBAA2BA,oEAASA,EAATwG,MAASmb,0BAChC3hB,uBACAA,8BACJA,+CAhBkCA,qCAe9BA,uFAlBhBA,SACIA,yBAqBJA,kDA1RJA,WACIA,iBAAmC,UAAnCA,CAAmC,gDAGvBA,+BACIA,iEAOJA,UAEJA,uDACIA,gCACIA,qEAOJA,YAGRA,mBACIA,yCAIJA,UAEJA,mBAAwB,YAAxBA,CAAwB,YAAxBA,CAAwB,oBAURA,qEAAUA,EAAVwG,MAAU9E,wBACb1B,UAELA,mBAAiC,YAAjCA,CAAiC,YAAjCA,CAAiC,aAIjBA,2CAaAA,6CAQJA,QACAA,mBAAmB,yBAAnBA,CAAmB,YAEJA,gCAAiCA,QACxCA,yCAOAA,yCAOJA,UAEJA,wCAMJA,QACAA,mBACIA,6CAmBAA,gCAAqB,YAEZA,gCACDA,sDAGHA,QACDA,+CAUJA,QACAA,gBAAoE,eAE3DA,gCACDA,sDAGHA,QACDA,mBACIA,UACJA,UAEJA,gBAAoE,eAE3DA,gCACDA,sDAGHA,QACDA,mBACIA,UACJA,YAIRA,mBAAoC,YAApCA,CAAoC,eAMvBA,gCACCA,sDAGLA,QACDA,mBAAkB,0BAEVA,+CAUJA,QACAA,+BACIA,+CAUAA,kBACKA,gCAEEA,kBAO3BA,mBAA2B,aAEnBA,8BASJA,gBAKhBA,mBAAwB,aAEhBA,+BACAA,0BAiBAA,mBACAA,mBACIA,2CAMAA,6BAQJA,YAGRA,mCAuBJA,+EA3RgEA,qBAGvBA,2DAMjBA,2DAAgD,yCAK9BA,4DAMlBA,4DAAgD,0CAOvCA,sDAUbA,6BAAgB,+FAAhBA,CAAgB,oHAAhBA,CAAgB,wCAcHA,sDAAoC,0BAuB9BA,6CAEFA,kDAOAA,iDASTA,6CAAuC,8BAAvCA,CAAuC,6CAAvCA,CAAuC,8CAOpBA,sDAqBdA,4DAEGA,uEAIJA,iEAGAA,yCAAyC,4CAAzCA,CAAyC,0CAO5CA,iEAEIA,8DAEGA,yEAIJA,yCAGHA,iEAEIA,6DAEGA,wEAIJA,mDAQJA,iEAGKA,8DAEGA,gFAQIA,2DAAoD,4CAApDA,CAAoD,+GAcpDA,2FAMCA,gGAWsBA,6CAgBlCA,2BACXA,wCAoByBA,2DAMtBA,iFAnQzBA,iBASIA,mCA4RJA,oDA9RIA,6FAEeA,4GCoChB,SA4BHG,YACYC,EACAC,EACAC,GAFAK,sBACAA,oBACAA,mBAnBFA,qBAAkB,IAAIX,MACtBW,uBAAoB,IAAIX,MAIxBW,iBAAc,IAAIX,MAClBW,qBAAkB,IAAIX,MACtBW,yBAAsB,IAAIX,MACpCW,wBAA+B,GAC/BA,kBAAe,IAAI8O,IACnB9O,gBAAaT,MAGJS,sBAAmB,CAACT,oBAA0BA,qBASvDa,WACIJ,KAAKmB,YAAY2W,SAASmJ,kBAAkB,eAAe5V,QAAQ7J,UAAU,EAAG0f,qBAC5ElhB,KAAKmhB,qBAAuB1hB,EAAe2hB,eAC3CphB,KAAKqhB,0BAA4B5hB,EAAe6hB,oBAChDthB,KAAK0G,eAAeC,iBAExB3G,KAAK0R,aAAe1R,KAAKif,UAAUpX,aAAarG,UAAU,IAAMxB,KAAK0G,eAAeC,gBAEpF3G,KAAK0R,aAAaqM,IACd/d,KAAKif,UAAUpX,aACVnE,MACG,OAAIjE,GAASA,EAAMqC,WACnB8J,KAAa,IACb,UAEHpK,UAAU,KACPxB,KAAKkf,uBAIjBlf,KAAKkf,oBAGTre,cACQb,KAAK0R,cACL1R,KAAK0R,aAAaK,cAI1BwP,iBAAiB9hB,GACb,OAAOA,IAAgB+hB,MAG3BC,UAAUhiB,EAAeC,GACrB,OAAOA,EAAK4B,GAGhBogB,sBAAsBjiB,SAClB,MAAME,EAAgD,QAA/BD,IAAUsB,IAAI,yBAAiB,eAAEO,MACxD,OACI5B,IAAmBJ,aAClBI,IAAmBJ,gBAAoD,IAA9BS,KAAKmhB,qBAIvDQ,mBAAmBliB,GACf,MAAMC,EAAUD,EAAMuB,IAAI,CAAC,kBAC3B,GAAItB,GAAWM,KAAK0Z,cAAe,CAC/B,MAAM/Z,EAAQK,KAAK0Z,cAAcrN,KAAKzM,GAAKA,EAAE0B,KAAO5B,EAAQ6B,OAC5D,OAAO5B,EAAQA,EAAMW,KAAO,GAEhC,MAAO,GAGXshB,uBAAuBniB,WAInB,OAHgF,QAA3CC,IAAQsB,IAAI,uCAA+B,eAAEO,OAC5EvB,KAAKqhB,0BAC6B,QAAlC1hB,IAAQqB,IAAI,8BAAsB,eAAEO,MAI9CsgB,sBAAsBpiB,GAClB,MAAMC,EAA+BD,EAAQqiB,6BACvC9hB,KAAKqhB,0BACL5hB,EAAQ6hB,oBACd,OAAO7hB,EAAQib,YAAcjb,EAAQsiB,eAAiBriB,EAG1DsiB,iBACI,QAAShiB,KAAKoa,UAAYpa,KAAKiiB,mBAAmBngB,SAAW9B,KAAKoa,SAAStY,OAG/Ef,cAActB,EAAmBC,GAC7BM,KAAKkiB,YAAYjb,KAAItG,eACjBwhB,aACGziB,IAEP,MAAMC,EAAQK,KAAKif,UAAUlJ,SAAS7B,UAAUtU,GAAKA,EAAE2B,MAAMD,KAAO7B,GACpEO,KAAKif,UAAUmD,GAAGziB,GAAOuB,cAG7BmhB,kBACQriB,KAAKgiB,iBACLhiB,KAAKiiB,mBAAqB,GAE1BjiB,KAAKiiB,mBAAqBjiB,KAAKoa,SAASxX,IAAInD,GAAKA,EAAE6B,IAEvDtB,KAAKsiB,gBAAgBrb,KAAKjH,KAAKiiB,oBAGnCM,oBAAoB9iB,GAChB,MAAMC,EAAQM,KAAKiiB,mBAAmBO,QAAQ/iB,IAC1C,EAAKC,EACLM,KAAKiiB,mBAAmB/U,OAAOxN,EAAO,GAEtCM,KAAKiiB,mBAAmBnV,KAAKrN,GAEjCO,KAAKsiB,gBAAgBrb,KAAKjH,KAAKiiB,oBAGnC5C,gBAAgB5f,SACZ,MAAME,EAAQK,KAAKma,aAAa9N,KAAKzM,GAAKA,EAAE0B,KAAO7B,GACnD,GAAIE,EAIA,OAFyE,QAArED,EAAK,MAALC,OAAK,EAALA,EAAOwW,aAAa9J,KAAKxM,GAAKA,EAAE0O,eAAiBvO,KAAK0f,uBAAe,QACrE/f,EAAMwW,aAAa,IACJ7V,KAI3BmiB,WAAWhjB,SAGP,OADyE,QAArEC,IAAOyW,aAAa9J,KAAKzM,GAAKA,EAAE2O,eAAiBvO,KAAK0f,uBAAe,QAAIjgB,EAAO0W,aAAa,IAC9E7V,KAGvBoiB,4BAA4BjjB,SACxB,OAAgD,QAAzCC,OAAKijB,yBAAyBljB,EAAQ6B,WAAG,QAAI7B,EAAQmjB,YAGhE9B,iBAAiBrhB,GACb,OAAOO,KAAK+E,aACPqB,cAAcqR,GAA2B,CACtCpR,KAAM,KACNQ,UAAU,IAEbrF,UAAU9B,IACP,GAAIA,EAAa,CACb,MAAMC,EAAwBF,EAAUA,EAAQmjB,YAAYhgB,IAAI/C,GAAMA,EAAGyB,IAAM,GACzE1B,EAAmBI,KAAKif,UAAUlJ,SAAS1J,KAAKxM,GAAKA,EAAE0B,MAAMD,KAAO7B,EAAQ6B,IAClF,GAAI1B,EAAkB,CAClB,MAAMC,KAAsByG,KAAO,IAC5B3G,KACAD,EAAYkD,IAAI9C,GAAMA,EAAGwB,MAEhC1B,EAAiBoO,WAAW,CAAE6U,cAAehjB,IAC7CD,EAAiBsB,cACZlB,KAAK2iB,yBAAyBljB,EAAQ6B,MACvCtB,KAAK2iB,yBAAyBljB,EAAQ6B,IAAM7B,EAAQmjB,YAAYzc,MAAM,IAE1EnG,KAAK2iB,yBAAyBljB,EAAQ6B,IAAIwL,QAAQpN,GAEtDM,KAAK0G,eAAeC,kBAKpCka,iBAAiBphB,EAAiCC,GAC9C,MAAMC,EAAYK,KAAKsf,aAAate,IAAIvB,EAAQ6B,IAChD,GAAI3B,EAAW,CACX,MAAMC,EAAYD,EAAU4B,MAA2BshB,cAAc5f,OACjEpD,GAAMA,IAAOH,GAEjBC,EAAUqO,WAAW,CACjB6U,cAAejjB,IAEnBD,EAAUuB,cACLlB,KAAK2iB,yBAAyBljB,EAAQ6B,MACvCtB,KAAK2iB,yBAAyBljB,EAAQ6B,IAAM7B,EAAQmjB,YAAYzc,MAAM,IAE1EnG,KAAK2iB,yBAAyBljB,EAAQ6B,IAAMtB,KAAK2iB,yBAAyBljB,EAAQ6B,IAAI2B,OAClFpD,GAAMA,EAAGyB,KAAO5B,IAK5BojB,kBAAkBrjB,GACd,OAAO,EAAKO,KAAKiiB,mBAAmBO,QAAQ/iB,GAGhDmhB,WAAWnhB,GACPO,KAAK+E,aACAqB,cAAc0Z,GAAoC,CAC/CzZ,KAAM,KACNS,OAAQ,CACJ2Y,cAAehgB,EACfigB,eAAgB1f,KAAK0f,eACrBxf,aAAcF,KAAK+iB,sBAG1BvhB,UAAU9B,IACHA,GACAM,KAAKsb,oBAAoBrU,KAAKvH,KAKtCwf,oBACJlf,KAAKsf,aAAapR,QAClB,UAAWzO,KAAgBO,KAAKif,UAAUlJ,SACtC/V,KAAKsf,aAAa1R,IAAInO,EAAa8B,MAAMD,GAAI7B,GAEjDO,KAAK0G,eAAeC,eAGhBqc,iBAAiBvjB,SAErB,OAD6D,QAAzBC,OAAK4f,aAAate,IAAIvB,UAAG,eAAE8B,OAC9CshB,sDAvOZI,IAA4B5jB,kEAA5B4jB,GAA4BhhB,k8GD9CzC5C,iBACIA,4CAsSJA,eAnSqCA,gFACb,+rIEDZA,8BACIA,mBAMAA,iBAAOA,8BAAkCA,gCAFrCA,4DAEGA,sFAafA,oBAGIA,iDAASoL,WAGTpL,8BACJA,gCAHIA,6FAEAA,6FAGAA,oBAGIA,kDAASC,SAKTD,8BACJA,iCALIA,+GAIAA,sIARJA,iCACKA,8EAgC+BA,uBAGIA,uEAAaA,EAAbwG,OAAakb,0BAEb1hB,gCAGAA,uCACJA,0CAHQA,qCAEJA,qEATRA,SACIA,8BAUJA,6CATSA,6FAPjBA,iDAIIA,kBACIA,mDAYAA,qBAA2BA,kDAAS2hB,oBAChC3hB,uBACAA,8BACJA,qCAnBJA,4CAIsCA,wDAc9BA,uFApBhBA,SACIA,mCAuBJA,gCAzBJA,SACIA,kCAyBJA,yFA8CAA,sBAAkE,WACvDA,8BAAwCA,QAC/CA,gEAMJA,+BAPWA,kDAGHA,8CAA6B,sDAA7BA,CAA6B,6EAoBrCA,mCAIIA,4DAAUA,EAAVwG,OAAUqd,yDACb7jB,oCAHGA,sBAAyB,6EAI7BA,qBAGIA,kDAAS8jB,4BAET9jB,uBACAA,8BACJA,cADIA,kGAMhBA,eAA4B,QACpBA,8BAA4CA,QAChDA,4CACIA,qFACHA,gBAHGA,gLAvHZA,2BAAmE,WAAnEA,CAAmE,WAAnEA,CAAmE,gBAInDA,mDA2BAA,kDACIA,oBAKIA,0CAASA,EAATwG,OAASgF,sDALbxL,UAQJA,qCAMIA,iCACIA,qBAMAA,kBAAOA,gCAELA,YAGVA,0EAKIA,+CAMJA,QACAA,oFAMAA,+BASAA,gDAKJA,UAEJA,mBAA6B,oBAKrBA,qEACHA,QACDA,mBACIA,6DAMAA,6BAQJA,YAIRA,4CAMJA,qDAxH+BA,6CA2BCA,2DAKRA,oDAMJA,8GAWWA,wEAMXA,oDAAoC,iEAQhCA,qDAKJA,qDAAkE,2CAI/BA,6CAWnCA,oCAAmB,2BAOvBA,yDAAgD,8DAAhDA,CAAgD,yCAOrBA,sDAOtBA,+CAUXA,yHA2CEA,gBAKIA,uBACAA,8BACJA,eALIA,gCAIAA,uGAIRA,kBAAqF,oCAG7EA,uDAAsBA,EAAtBwG,OAAsBud,sCACzB/jB,QAEDA,sCAIIA,+CAAcA,EAAdwG,OAAcwd,gEACjBhkB,yCATGA,0DAKAA,wEAAsC,wCAAtCA,CAAsC,uEAO9CA,kIAEIA,yCAA8B,kDAA9BA,CAA8B,8BAA9BA,CAA8B,iEAA9BA,CAA8B,wDAA9BA,CAA8B,uFAOlCA,wCAaIA,oDAAmBA,EAAnBwG,OAAmByd,2BAAnBjkB,CAAkD,gDAC7BA,EAD6BwG,OAC7B0d,6BADrBlkB,CAAkD,0CAEnCA,EAFmCwG,OAEnC2d,uBAFfnkB,CAAkD,kDAG3BA,EAH2BwG,OAG3ByV,wBAHvBjc,CAAkD,mKAKrDA,gDAhBGA,0CAA8B,mDAA9BA,CAA8B,iEAA9BA,CAA8B,sDAA9BA,CAA8B,8BAA9BA,CAA8B,wDAA9BA,CAA8B,6CAA9BA,CAA8B,qCAA9BA,CAA8B,0CAA9BA,CAA8B,6CAA9BA,CAA8B,uFAkBtCA,kBAAqF,oCAG7EA,uDAAsBA,EAAtBwG,OAAsBud,sCACzB/jB,QAEDA,sCAIIA,+CAAcA,EAAdwG,OAAcwd,gEACjBhkB,yCATGA,0DAKAA,wEAAsC,wCAAtCA,CAAsC,sFA3FlDA,2BAAoE,eAApEA,CAAoE,WAApEA,CAAoE,WAApEA,CAAoE,eAMhDA,qEAA8B,SAG9BA,uBACAA,mBAAyBA,8BAAiDA,UAE9EA,qBAEIA,qEAA8B,UAG9BA,wBACAA,oBAAyBA,gCAAiDA,YAGlFA,mBACIA,2CAIAA,sBAA4BA,yCAASA,EAATwG,OAAS4d,qBAAqB,MACtDpkB,wBACJA,UAEJA,mBACAA,wBAQJA,QAEAA,6CAcAA,kDASAA,iDAmBJA,QACAA,6CAaJA,yCA1FoBA,4DAGyBA,4DAKzBA,6DAGyBA,6DAKzBA,4CAA2B,4DAS9BA,+CASwBA,yFAe5BA,sDASAA,qDAmBwBA,mIAxFzCA,mBAAmC,eACZA,yCAASA,EAATwG,OAAS6d,cAAc,cACtCrkB,8BACJA,QACAA,wDAkGJA,iCApGQA,8DAEcA,6GAzI9BA,mBACIA,qBACAA,oBAAU,YAAVA,CAAU,eAEiBA,iDAASqkB,cAAc,aACtCrkB,8BACJA,QACAA,wDA6HJA,QACAA,+CAuGJA,kCA5OeA,gCAKHA,6DAEcA,kEA8HZA,8CCnHX,iBACKE,MA+BRC,YACIC,EACAC,EACAC,EACQC,EACAC,EACAC,EACAwC,EACEI,EACFH,EACAE,GAER1C,MAAMN,EAAOC,EAAQC,EAAqB+C,GARlC1C,4BACAA,mBACAA,oBACAA,2BACEA,mBACFA,gBACAA,sBA7BZA,iBAAc,IAAIC,KAAY,IAC9BD,kBAA+B,GAC/BA,yBAA+D,GAC/DA,8BAA2F,GAI3FA,kBAAe,IAAIkC,IAAgB,GACnClC,mBAAgB,IAAIkC,IAAgB,IAEpClC,wBAA+B,GAC/BA,wBAAuC,OACvCA,0BAAoD,CAAE6Z,OAAQ,GAAIO,SAAU,IAIpEpa,uBAAoB,IAAI8O,IAChB9O,uBAAoB,CAACT,oBAA0BA,qBAe3DS,KAAKE,aAAeF,KAAKG,qBAAqB,WAC9CH,KAAK2jB,oBAAsB3jB,KAAKG,qBAAqB,kBACrDH,KAAK4jB,wBAA0B5jB,KAAKG,qBAAqB,sBACzDH,KAAK+iB,mBAAqB/iB,KAAKG,qBAAqB,iBACpDH,KAAKK,WAAaL,KAAKQ,YAAYC,MAAM,CACrCW,QAASpB,KAAKQ,YAAYC,MAAM,CAC5Bme,SAAS,EACTte,KAAM,CAAC,GAAIL,eACX4jB,wBAAwB,EACxB/Y,KAAM,CAAC,MAAIvL,OAAwB,yBACnCwL,YAAa,GACb8X,cAAe,CAAC,IAChB3iB,aAAcF,KAAKQ,YAAYC,MAC3BT,KAAKE,aAAaQ,OAAO,CAACmC,EAAM8F,IAAUhI,+BAAMkC,GAAI,EAAG8F,EAAMrI,MAAO,KAAO,OAGnF8Z,SAAUpa,KAAKQ,YAAYyK,MAAM,MAIzC7K,WACIJ,KAAKY,OACLZ,KAAK8jB,SAAW9jB,KAAKkM,QACrB,MAAMzM,EAAcO,KAAKyjB,YAAY5b,aAAanE,MAC9C,QAAU,OACVkI,KAAa,QACb2F,WACAzJ,KAAI,IAAM9H,KAAKwD,aAAamG,KAAK,KAE/BjK,EAAmBM,KAAK8jB,SAASpgB,QAAKC,KAAIjB,GAAKA,EAAEyW,YAAY/U,QAC7DzE,GAAgB,OAAcF,EAAaO,KAAKwD,aAAcxD,KAAKuD,eAAeG,KdxIzF,eACP,OAAW,QAAO,QAClB,SACA,SAA+B,QAAwBhE,OACvD,yBACAC,MACWokB,OACH,SAASlV,gBACjBpP,eAAyBukB,MAAwBtkB,sBciIrCukB,CAAUvkB,IACV,QAAK,IACL,OAAa,MACb,OAAU,EAAEgD,EAAMH,EAAaE,KACpBzC,KAAKmB,YAAYC,QACnB4Z,mBAAkBra,6BAEXoC,MAAOR,EAAc,GAAKE,EAC1BO,KAAMP,GACFC,EACE,CAAEO,OAAQ,CAAE3C,KAAM,CAAE4C,SAAUR,GAAQ+X,IAAK,CAAEvX,SAAUR,KACvD,IAAG,CACTwhB,eAAgB3kB,WAEpBS,KAAKsB,IAER6C,UAAU,EAAGmF,qBAAsBzG,KAE5C,QAAY,CAAEshB,WAAY,EAAGC,UAAU,KAErCxkB,EAAmBD,EAAc+D,MAAK,OAAIhB,GAAUA,EAAO0B,QACjEpE,KAAKqkB,aAAYC,MAAM5kB,EAAkBE,GAAkB8D,MACvD,OAAIhB,IACA,UAAWH,KAAWG,EAClB1C,KAAKukB,kBAAkB3W,IAAIrL,EAAQjB,GAAIiB,MAInDvC,KAAKyD,eAAc6gB,MACftkB,KAAK8jB,SAASpgB,MAAK,OAAIhB,GAAWA,EAAQyW,YAAYrV,aACtDnE,EAAc+D,MAAK,OAAIhB,GAAUA,EAAOoB,cAE5C9D,KAAKsD,mBAAoB,OAActD,KAAKyD,YAAazD,KAAKuD,cAAevD,KAAKwD,cAAcE,QAC5FC,KAAI,EAAEjB,EAAYH,EAAcE,MAAkB,CAC9CqB,aACAF,eACAC,kBAGR7D,KAAKwkB,eAAiBxkB,KAAKykB,qBAAqBhL,mBAAmB/V,MAAK,OAAU1D,KAAK+D,WACvF/D,KAAK0kB,WAAa1kB,KAAKwH,MAAMyE,SAASvI,QAAKC,KAAIjB,GAAOA,EAAI1B,IAAI,UAE9D,OAAcpB,EAAkBI,KAAK0M,eAChChJ,QAAKmT,KAAU7W,KAAK+D,WACpBvC,UAAU,EAAEkB,EAAUH,MACnBvC,KAAK2kB,sBAAsBjiB,EAAUH,KAG7C,MAAM1C,EAAsBG,KAAK8jB,SAASpgB,QAAKC,KAAIjB,GAAWA,EAAQkgB,cAGhEtgB,EAA2BtC,KAFP4kB,sBAEoB5jB,IAAI,iBAAkB6G,aAAanE,MAC7E,QAAK,IACL,YACA+B,KAAU/C,GACN1C,KAAKmB,YAAY4T,MACZ8P,eAAe,CAAE5hB,OAAQ,CAAE3B,GAAI,CAAEwjB,GAAIpiB,MACrCyG,UAAU,EAAGyZ,iBAAkBrgB,EAAY6B,WAEpDmN,MAAY,IAEhBvR,KAAK+kB,gBAAeC,MAChBnlB,EAAoB6D,MAAK,OAAK,IAC9B7D,EAAoB6D,Kd1MzB,iBACP,OAAW,QAAUjE,MAAmBgG,KAAS,UAA0C,OAAS,OcyM/Dwf,CAAY3iB,KAEzCtC,KAAKklB,iBAAmBllB,KAAK8jB,SAASpgB,QAAKC,KAAIjB,GAAKA,EAAEsV,WACtDhY,KAAKmlB,yBAA2BnlB,KAAKmB,YAAY2W,SAC5CwG,iBAAiB,eACjBnL,yBACAhP,UAAUzB,GAAQA,EAAK8b,cAAc4G,kBACrC1hB,QAAK6N,MAAY,IAG1B1Q,cACIb,KAAKc,UAGT4iB,cAAcjkB,GACVO,KAAKqlB,SAASC,aACVtlB,KAAKkK,OACAqb,cAAc,CAAC,KAAI5kB,+BAAOX,KAAKwH,MAAM8F,SAAS6G,QAAM,CAAEqR,IAAK/lB,KAAY,CACpE6K,oBAAqB,QACrBF,WAAYpK,KAAKwH,QAEpB6O,YAIbkL,iBAAiB9hB,GACb,OAAOA,IAAgB+hB,MAG3B6B,QAAQ5jB,GACJO,KAAKwD,aAAamG,KAAKlK,GAG3B2jB,gBAAgB3jB,GACZO,KAAKuD,cAAcoG,MAAMlK,GACzBO,KAAKwD,aAAamG,KAAK,GAG3BqX,kBACIhhB,KAAKklB,iBACAxhB,MACG,OAAK,MACL+B,KAAUhG,GACCO,KAAK+E,aAAaqB,cAAciT,EAAwC,CAC3EhT,KAAM,KACNS,OAAQ,CACJmS,WAAY,CAACjZ,KAAKsB,IAClBmkB,kBAAmBhmB,EAASmD,IAAIlD,GAAKA,EAAE4B,SAKtDE,YAGTuf,kBAAkBthB,MACd6Y,OAAK,SAA6BtY,KAAKmB,YAAa1B,IAC/CiE,QACG+B,KAAU,EAAGigB,iBACF1lB,KAAK+E,aAAaC,OAAO,CAC5BC,SAAOC,KAAE,uCACTG,QAAS,CACL,CAAEC,KAAM,YAAaC,SAAOL,KAAE,kBAC9B,CACII,KAAM,SACNC,SAAOL,KAAE,+BACTC,gBAAiB,CAAEugB,eACnBlgB,aAAa,UAK7BC,KAAU/F,GACNA,EACMM,KAAKmB,YAAYC,QAAQukB,0BAA0B,CAC/C9M,YACAI,WAAY,CAACjZ,KAAKsB,MAEtBoE,MAGblE,UACG,KACIxB,KAAKyB,oBAAoBC,WAAQwD,KAAE,wDAEvCxF,IACIM,KAAKyB,oBAAoBG,SAAMsD,KAAE,uDAKjDoe,uBAAuB7jB,GACnB,OAAOO,KAAK+E,aACPqB,cAAciT,EAAwC,CACnDhT,KAAM,KACNS,OAAQ,CACJmS,WAAY,CAACjZ,KAAKsB,IAClBsW,kBAAmB,CAACnY,EAAQ6B,IAC5BmkB,kBAAmBhmB,EAAQuY,SAASpV,IAAIlD,GAAKA,EAAE4B,OAGtDE,YAGT+hB,0BAA2B1K,YAAW+M,eAClCtN,OAAK,SAA6BtY,KAAKmB,YAAa1B,IAC/CiE,QACG+B,KAAU,EAAGigB,iBACF1lB,KAAK+E,aAAaC,OAAO,CAC5BC,SAAOC,KAAE,+CACTG,QAAS,CACL,CAAEC,KAAM,YAAaC,SAAOL,KAAE,kBAC9B,CACII,KAAM,SACNC,SAAOL,KAAE,+BACTC,gBAAiB,CAAEugB,eACnBlgB,aAAa,UAK7BC,KAAU9F,GACNA,EACMK,KAAKmB,YAAYC,QAAQykB,0BAA0B,CAC/ChN,YACAjB,kBAAmB,CAAClY,EAAQ4B,MAEhCoE,MAGblE,UACG,KACIxB,KAAKyB,oBAAoBC,WAAQwD,KAAE,wDAEvCvF,IACIK,KAAKyB,oBAAoBG,SAAMsD,KAAE,uDAKjDqH,gBACI,QAAS5L,OAAO6L,OAAOxM,KAAKyM,cAAc3K,OAG9CgkB,uBACI,QAASnlB,OAAOolB,KAAK/lB,KAAKgmB,qBAAqBlkB,OAGnD0hB,mBAAmB/jB,GACfO,KAAKgmB,oBAAoBvmB,EAAM0iB,WAAa1iB,EAMhDoL,WAAWpL,IACP,OAAcO,KAAKkM,QAASlM,KAAK0M,eAC5BhJ,QAAKiJ,KAAK,IACVnL,UAAU,EAAE9B,EAAQC,MACjB,MAAMC,EAAcI,KAAKK,WAAWW,IAAI,CAAC,UAAW,SAC9CnB,KAAqBN,OAAgBG,EAAQC,GAC7CG,GAAsBD,IAAuBA,EAAmBiL,KAClElL,GAAeA,EAAYgN,UAAY9M,GACvCF,EAAYqB,UAAS,QAAgB,GAAGxB,IAAa,QAKrE0jB,0BACInjB,KAAKimB,yBAAyBzkB,UAAU/B,IACpC,GAAIA,EAAe,CACf,MAAMC,EAAeM,KAAK4kB,sBACpBjlB,EAAuBD,EAAa6B,MAAMshB,cAChDnjB,EAAasO,WAAW,CACpB6U,eAAe,OAAO,IAAIljB,KAAyBF,MAEvDC,EAAawB,iBAKzBoa,oBAAoB7b,IAChB,OAAcO,KAAK8jB,SAAU9jB,KAAK0M,eAC7BhJ,QACGiJ,KAAK,IACL,OAAS,EAAEjN,EAASC,KAChBK,KAAKykB,qBAAqBnJ,oBAAoB7b,EAAOC,EAASC,KAGrE6B,UACG,KACIxB,KAAKyB,oBAAoBC,SAAQ,OAAE,gCAAiC,CAChEC,OAAQ,mBAGhBjC,IACIM,KAAKyB,oBAAoBG,OAAM,OAAE,8BAA+B,CAC5DD,OAAQ,oBAM5BuhB,wBAAwBzjB,GACpB,MAAMC,EAAeM,KAAK4kB,sBACpBjlB,EAAuBD,EAAa6B,MAAMshB,cAChDnjB,EAAasO,WAAW,CACpB6U,cAAeljB,EAAqBsD,OAAOrD,GAAMA,IAAOH,KAE5DC,EAAawB,cAGjBglB,2BACI,OACI,EAAIlmB,KAAKmmB,qBAAqB/L,SAAStY,QACvC9B,KAAKmmB,qBAAqB/L,SAASgM,MAAM3mB,GACpB,KAAVA,EAAEgb,KAKbwL,yBACJ,OAAOjmB,KAAK+E,aACPqB,cAAcqR,GAA2B,CACtCpR,KAAM,KACNQ,UAAU,IAEbnD,QAAKC,KAAIlE,GAAeA,GAAeA,EAAYmD,IAAIlD,GAAKA,EAAE4B,MAGvEmJ,SACI,MAAMhL,EAAeO,KAAK4kB,uBACrBnlB,EAAa0N,UAGlBC,KAAcpN,KAAK8jB,SAAU9jB,KAAK0M,eAC7BhJ,MACG,OAAK,IACL,OAAS,EAAEhE,EAASC,MAChB,MAAMC,EAAaI,KAAKqmB,kBACpB3mB,EACAD,EACAE,GAEJ,OAAOK,KAAKykB,qBAAqB9K,0BAC7B/Z,EACAI,KAAKmmB,qBACLxmB,MAIX6B,UACG,EAAG+Y,wBAAuBN,gBACtBja,KAAKyB,oBAAoBC,SAAQ,OAAE,gCAAiC,CAChEC,OAAQ,YAEZ3B,KAAKyM,aAAe,GACpBzM,KAAKgmB,oBAAsB,GAC3BhmB,KAAKK,WAAWmN,iBAChBxN,KAAKkK,OAAOC,SAAS,CAAC,MAAOxK,GAAY,CAAEyK,WAAYpK,KAAKwH,SAEhE9H,IAEI4mB,QAAQ1kB,MAAMlC,GACdM,KAAKyB,oBAAoBG,OAAM,OAAE,8BAA+B,CAC5DD,OAAQ,cAM5BrC,UACI8N,KAAcpN,KAAK8jB,SAAU9jB,KAAK0M,cAAe1M,KAAKmlB,0BACjDzhB,MACG,OAAK,MACLqW,KAAS,EAAEta,EAASC,EAAcC,cAC9B,MAAMG,EAAeE,KAAK4kB,sBAC1B,IAAItiB,EACAI,GAEA5C,EAAaqN,OAASnN,KAAKuM,mBAC3BjK,EAAetC,KAAKqmB,kBAChB5mB,EACAK,EACAJ,IAGR,MAAM6C,EAAgBvC,KAAKK,WAAWW,IAAI,YAC1C,OAAKuB,GAAiBA,EAAc4K,OAAUnN,KAAK8lB,0BAC/CpjB,EAAgB1C,KAAKumB,0BACjB9mB,EACA8C,EACA7C,EACAC,IAIDK,KAAKykB,qBAAqB7J,cAAc,CAC3CxZ,UACAmN,eACAsM,WACqE,QAAjEhb,EAA0D,QAA1DD,OAAKS,WAAWW,IAAI,CAAC,UAAW,kCAA0B,eAAEO,aAAK,SACrEuZ,eACAC,qBAIXvZ,UACG/B,IACIO,KAAKwmB,oBAAoB/mB,GACzBO,KAAKK,WAAWmN,iBAChBxN,KAAKyM,aAAe,GACpBzM,KAAKgmB,oBAAsB,GAC3BhmB,KAAKymB,yBAA2B,GAChCzmB,KAAKyB,oBAAoBC,SAAQ,OAAE,gCAAiC,CAChEC,OAAQ,YAEZ3B,KAAK0G,eAAeC,gBAExBlH,IACIO,KAAKyB,oBAAoBG,OAAM,OAAE,8BAA+B,CAC5DD,OAAQ,cAM5BgM,gBACI,OAAO5N,MAAM4N,kBAAoB3N,KAAKyM,aAAapK,SAAWrC,KAAKyM,aAAajG,cAM1E3E,cACNpC,EACAC,GAEA,MAAMC,GAAqB,SAAgBF,EAASC,GACpDM,KAAKK,WAAW2N,WAAW,CACvB5M,QAAS,CACLwd,QAASnf,EAAQmf,QACjBte,KAAMX,EAAqBA,EAAmBW,KAAO,GACrDwK,KAAMnL,EAAqBA,EAAmBmL,KAAO,GACrDC,YAAapL,EAAqBA,EAAmBoL,YAAc,GACnE8X,cAAepjB,EAAQmjB,YAAYhgB,IAAIhD,GAAMA,EAAG0B,OAIpDtB,KAAKE,aAAa4B,QAClB9B,KAAK+B,yBACD/B,KAAKE,aACLF,KAAKK,WAAWW,IAAI,CAAC,UAAW,iBAChCvB,EACAE,GAGRK,KAAK2kB,sBAAsBllB,EAAQ0Z,YAAY/U,MAAO1E,GAGlDilB,sBAAsBllB,EAAoCC,GAC9D,MAAMC,EAAoBK,KAAKK,WAAWW,IAAI,YAC9CvB,EAAS0O,QAAQ,CAACvO,EAASC,KACvB,MAAMC,KAAqBP,OAAgBK,EAASF,GAC9C4C,EAA2BtC,KAAKymB,yBAAyB7mB,EAAQ0B,IACjEoB,EAAgBJ,EAChBA,EAAyBM,IAAIC,GAAMA,EAAGvB,IACtC1B,EAAQgjB,YAAYhgB,IAAIC,GAAMA,EAAGvB,IACjCiB,EAA0B,CAC5BjB,GAAI1B,EAAQ0B,GACZsd,QAAShf,EAAQgf,QACjBnE,IAAK7a,EAAQ6a,IACbna,KAAMR,EAAqBA,EAAmBQ,KAAO,GACrDmY,MAAO7Y,EAAQ6Y,MACfiO,aAAc9mB,EAAQ8mB,aACtBhG,cAAe9gB,EAAQ+mB,YAAYrlB,GACnCoZ,YAAa9a,EAAQ8a,YACrBoH,6BAA8BliB,EAAQkiB,6BACtCR,oBAAqB1hB,EAAQ0hB,oBAC7BF,eAAgBxhB,EAAQwhB,eACxByB,iBAGJ,IAAIpgB,EAAmB9C,EAAkBoW,SAAS1J,KAAKxJ,GAAKA,EAAEtB,MAAMD,KAAO1B,EAAQ0B,IAcnF,GAXAmB,EACQA,EAAiBmK,UACjBnK,EAAiBuL,WAAWzL,IAGhCE,EAAmBzC,KAAKQ,YAAYC,MAAKE,+BAClC4B,GAAK,CACRsgB,cAAe7iB,KAAKQ,YAAYuM,QAAQrK,MAE5C/C,EAAkBwV,OAAOtV,EAAG4C,IAE5BzC,KAAK2jB,oBAAoB7hB,OAAQ,CACjC,IAAIe,EAAoBJ,EAAiBzB,IAAI,CAAC,iBAEzC6B,IACDA,EAAoB7C,KAAKQ,YAAYC,MACjCT,KAAK2jB,oBAAoBjjB,OAAO,CAACiI,EAAMC,IAAUjI,+BAAMgI,GAAI,EAAGC,EAAMtI,MAAO,KAAO,KAEtFmC,EAAiByS,WAAW,eAAgBrS,IAEhD7C,KAAK+B,yBACD/B,KAAK2jB,oBACL9gB,EACAjD,EACAE,MAURumB,kBACJ5mB,EACAC,EACAC,WAEA,MAAMG,KAAiBP,OAA0B,CAC7C6O,aAAc3O,EACd4O,cAAe3O,EAAiB6B,MAChC+M,kBAAmBtO,KAAKE,aACxBqO,eACAC,mBAAoB,CAChBD,eACAjO,KAAMb,EAAQa,MAAQ,GACtBwK,KAAMrL,EAAQqL,MAAQ,GACtBC,YAAatL,EAAQsL,aAAe,MAG5C,OAAOpK,+BACAb,GAAc,CACjB2O,SAAkC,QAAxB7O,OAAK6M,aAAapK,cAAM,eAAEO,IAAIN,GAAKA,EAAEhB,IAC/CoN,gBAAgD,QAA/B7O,OAAK4M,aAAajG,qBAAa,eAAElF,GAClDuhB,cAAenjB,EAAiB6B,MAAMshB,gBAQtC0D,0BACJ9mB,EACAC,EACAC,EACAC,GAEA,MAAMC,EAAoBH,EAAkBqW,SAAS9S,OAAOP,GAAKA,EAAEyK,OAC7DrN,EAAgBD,EACjB+C,IAAIF,GAAK1C,KAAKukB,kBAAkBvjB,IAAI0B,EAAEnB,MAAMD,KAC5C2B,OAAOqT,sBACNhU,EAAqBzC,EAAkB+C,IAAIF,GAAKA,EAAEnB,OAExD,GAAIzB,EAAcgC,SAAWQ,EAAmBR,OAC5C,MAAM,IAAIoO,SAAMhL,KAAE,mDAEtB,OAAOpF,EACF8C,IAAI,CAACF,EAASH,aACX,MAAMoG,EAA8BrG,EAAmB+J,KAAKvD,GAASA,EAAMxH,KAAOoB,EAAQpB,IACpFsH,KAAoCrJ,OAA0B,CAChE6O,aAAc1L,EACd2L,cAAe1F,EACf2F,kBAAmBtO,KAAK2jB,oBACxBpV,eACAC,mBAAoB,CAChBD,eACAjO,KAAM,MAGdsI,EAAO8X,cAAgB/X,EAAU+X,cACjC9X,EAAOia,cAAgBla,EAAUka,cACjCja,EAAO6P,MAAQ7Y,EAAmB+I,EAAU+d,aAAe/d,EAAU8P,MACrE,MAAM5P,EAAe7I,KAAKgmB,oBAAoBtjB,EAAQpB,IACtD,OAAIuH,IACAD,EAAO8F,gBAA4C,QAA1BjM,IAAa+D,qBAAa,eAAElF,GACrDsH,EAAO6F,SAA8B,QAAnB5L,IAAaR,cAAM,eAAEO,IAAIkG,GAAKA,EAAExH,KAE/CsH,IAEV3F,OAAOqT,sBAGRsO,sBACJ,OAAO5kB,KAAKK,WAAWW,IAAI,WAMvBwlB,oBAAoB/mB,GACxB,MAAMC,EAAcD,EAAQ,GACtBE,EAAcK,KAAKK,WAAWW,IAAI,CAAC,UAAW,SAMhDrB,GAJJ,WAA0BE,GACtB,OAAOA,EAAMoP,eAAe,iBAGbrP,CAAiBF,IAChCC,EAAYsB,SAASvB,EAAYkb,cAAc9P,KAAM,CAAE8b,WAAW,4CAroBjEC,IAAsBxnB,qJAAtBwnB,GAAsB5kB,i/GDjEnC5C,0BAAgB,gBAAhBA,CAAgB,WAGJA,8CACAA,uCASJA,QACAA,mCAIIA,8CAAsBK,sEACzBL,UAGLA,yBACIA,mCACAA,8CAQAA,4CAYJA,UAGJA,sEA5C6BA,8CACIA,+CAWrBA,gDAA2B,2DAA3BA,CAA2B,mDAW1BA,6CAAsB,cAqBUA,+zDEzBzBA,qKAIAA,SACIA,qBAIIA,iDAASynB,0DAGTznB,+BACAA,8BAIJA,QACAA,kBACJA,gCATQA,mDAGAA,sLAkCpBA,gBAKIA,uBACAA,8BACJA,eALIA,gCAIAA,2FA0BIA,+DAOIA,+DAGAA,kBACIA,uBACJA,mCAMRA,kBAAyCA,SAAgBA,mCAAhBA,8CAGzCA,oBAAkCA,8BAAmCA,eAAnCA,mLAvBtCA,iBAA2E,YAEnEA,yBASAA,4CAKJA,UAEJA,iBAAiE,SACxDA,SAAqEA,QAC1EA,yBACJA,QACAA,iBACIA,+BACJA,QACAA,kBACIA,0DAMAA,yBAAc,gBAENA,gCACAA,wBACJA,QACAA,gCAA8C,gBAItCA,sDAASA,EAATwG,MAASkhB,uDAIT1nB,wBACAA,gCACJA,0DA/C4BA,6BAG3BA,6FAIT,cAW0BA,sCACrBA,oEACCA,yCAEeA,sCACVA,kCAEgBA,sCAIvBA,mDAAmC,mCAK/BA,sDAQIA,sDAIAA,mHCnHjB,iBACKE,MAoBRC,YACYC,EACAC,EACAC,EACAC,EACAC,EACRC,EACAwC,GAEAvC,MAAMD,EAAQwC,GARNtC,mBACAA,oBACAA,2BACAA,uBACAA,2BAlBZA,gBAAa,GACbA,mBAA0B,GAC1BA,qBAAiB,EAKjBA,+BAA4B,EAgBxBA,KAAKwH,MAAMC,cACN/D,MACG,OAAIhB,GAAOA,EAAI1B,IAAI,OACnB,OAAUhB,KAAK+D,WAElBvC,UAAUkB,IACP1C,KAAKgnB,WAAatkB,GAAQ,GACtB1C,KAAKinB,oBACLjnB,KAAKinB,mBAAmBC,cAAcxkB,KAGlD1C,KAAKmnB,uBAAyBnnB,KAAKwH,MAAMC,cAAc/D,MAAK,OAAIhB,GAAOA,EAAI0kB,OAAO,WAElFpnB,KAAKmnB,uBAAuBzjB,MAAK,OAAU1D,KAAK+D,WAAWvC,UAAUkB,IACjE1C,KAAK6iB,cAAgBngB,EACjB1C,KAAKinB,oBACLjnB,KAAKinB,mBAAmBI,eAAe3kB,KAG/C3C,MAAMoC,WACF,IAAIO,IACA1C,KAAKmB,YAAYC,QAAQkmB,eAAetnB,KAAKgnB,cAAetkB,GAAMyQ,yBACtEzQ,GAAQA,EAAK6kB,OAEb,CAAC7kB,EAAMH,KAAU,CACbob,MAAO,CACH5a,OACAC,OACAwkB,KAAMxnB,KAAKgnB,WACXnE,cAAe7iB,KAAK6iB,cACpB4E,mBAAoBloB,UACpBmoB,eAAgB1nB,KAAK0nB,mBAIjC1nB,KAAK8Q,iBAAmB,IAAIvR,MAAiB,CACzCwT,aAAa,EACbC,cAAe,CAACtQ,EAAGH,IACfvC,KAAK0nB,eAAiBhlB,EAAEuX,YAAc1X,EAAE0X,UAAYvX,EAAEilB,mBAAqBplB,EAAEolB,iBACjF7U,cAAc,IAItB1S,WACIL,MAAMK,WAENJ,KAAK+kB,aAAe/kB,KAAK4nB,QAAQlkB,MAAK,OAAIjE,GAAQA,EAAK8nB,OAAO3E,cAE9D5iB,KAAK+kB,aACArhB,QAAKiJ,KAAK,IAAI,QAAM,QAAMkb,MAAe7nB,KAAKmnB,yBAC9C3lB,UAAU,EAAE/B,EAAIC,MACbM,KAAKinB,mBAAmBI,eAAe3nB,KAE/CM,KAAKwT,oBAAsBxT,KAAKyT,oBAAoBC,wBACpD1T,KAAK2T,iBAAmB3T,KAAKmB,YAAYiQ,OACpCwC,UACAzP,UAAU,EAAGyP,aAAcnU,EAAQoU,iBACnCnQ,MAAK,OAAI,IAAM1D,KAAKgE,YAEzBhE,KAAKmB,YAAYC,QACZ0mB,+BACA3e,UAAU,EAAG4e,+BAAgCtoB,GAC7C+B,UAAU/B,GAAUO,KAAK+nB,0BAA4BtoB,GAG9D0X,kBACQnX,KAAKinB,oBAAsBjnB,KAAKgnB,YAChC5P,WAAW,IAAMpX,KAAKinB,mBAAmBC,cAAclnB,KAAKgnB,aAIpEE,cAAcznB,GACVO,KAAKgnB,WAAavnB,EAClBO,KAAKgoB,cAAc,CAAElgB,EAAGrI,GAAQ,KAAMwoB,KAAM,IAC5CjoB,KAAKgE,UAGTkkB,iBAAiBzoB,GACbO,KAAK6iB,cAAgBpjB,EACrBO,KAAKgoB,cAAc,CAAEG,MAAO1oB,EAAKwoB,KAAM,IACvCjoB,KAAKgE,UAGTokB,qBACIpoB,KAAKmB,YAAYC,QAAQinB,UAAU7mB,UAAU,EAAG6mB,cAC5CroB,KAAKyB,oBAAoB6mB,QAAKpjB,KAAE,uBAChClF,KAAKuoB,gBAAgBC,OAAO/oB,EAAQ6B,GAAI5B,IACpC,GAAIA,EAAI+oB,QAAUlpB,gBAAoB,CAClC,MAAMI,GAAO,IAAI+oB,KAAKC,cAAeC,OAAOlpB,EAAImpB,UAAY,GAC5D7oB,KAAKyB,oBAAoBC,SAAQ,OAAE,8BAA+B,CAC9DiD,MAAOjF,EAAIoF,OAAOgkB,iBAClBC,SAEJ/oB,KAAKgE,eAELhE,KAAKyB,oBAAoBG,SAAMsD,KAAE,8BAMjD4hB,+BACI9mB,KAAKmB,YAAYC,QAAQ0lB,+BAA+BtlB,UAAU/B,IAC9DO,KAAKyB,oBAAoB6mB,MAAK,OAAE,wCAAyC,CACrE3jB,MAAO3E,KAAK+nB,4BAEhB/nB,KAAK+nB,0BAA4B,IAIzChB,cAActnB,GACVO,KAAK+E,aACAC,OAAO,CACJC,SAAOC,KAAE,kCACTG,QAAS,CACL,CAAEC,KAAM,YAAaC,SAAOL,KAAE,kBAC9B,CAAEI,KAAM,SAAUC,OAAO,OAAE,iBAAkBC,aAAa,MAGjE9B,MACG,OAAUhE,GAAaA,EAAWM,KAAKmB,YAAYC,QAAQ2lB,cAActnB,GAAaiG,MAGtF,QAAM,MAETlE,UACG,KACIxB,KAAKyB,oBAAoBC,SAAQ,OAAE,gCAAiC,CAChEC,OAAQ,YAEZ3B,KAAKgE,WAETtE,IACIM,KAAKyB,oBAAoBG,OAAM,OAAE,8BAA+B,CAC5DD,OAAQ,cAM5B0S,YAAY5U,GACRO,KAAKmB,YAAYiQ,OAAOkD,mBAAmB7U,GAAM+B,sDCpL7CnC,oBAGIA,iDAASC,SAGTD,8BACJA,gCAHIA,8DAEAA,8EAyCYA,iBAIC,WAEOA,8BACJA,QACAA,iBACIA,6CAKJA,QACAA,iBAAyBA,oBAA4CA,yDAZrEA,yBAGqBA,iCAMbA,qFA9ChCA,kBAA+F,eAA/FA,CAA+F,YAGnFA,8BACAA,kBAAiBA,SAA4BA,UAEjDA,kBAAwB,4CAEhBA,8CAMJA,QACAA,oDACIA,+CAMJA,UAEJA,uBAA4B,cAA5BA,CAA4B,WAA5BA,CAA4B,SAIZA,eACAA,eAAIA,gCAA+BA,QACnCA,eAAIA,gCAA+BA,YAG3CA,kBACIA,yBAiBJA,+DAlDUA,kCAEGA,iCACAA,6BAGDA,kDAERA,+BAAkB,6CAMVA,mDAERA,+BAAkB,6CAYVA,2CACAA,2CAMeA,qEAtCnDA,kBAA0F,WAElFA,0BAwDJA,gCA1DeA,gCAEkDA,sFDLxD2pB,IAAoB3pB,oHAApB2pB,GAAoB/mB,ovDD9BjC5C,0BAAgB,kBAAhBA,CAAgB,UAAhBA,CAAgB,kCAMAA,4CAAoBK,oBAApBL,CAA0C,sCACtBK,yCACvBL,QACDA,0BAA+C,mCAYvCA,sBACAA,sCACJA,QACAA,gCAA8C,WACdA,gCAAiDA,QAC7EA,oCAgBAA,sBAGIA,gCAASK,mDAGTL,gCACJA,cAIZA,mBAAuB,2BAAvBA,CAAuB,eAEkBA,8DAA4B,kCAAkBK,cAA/EL,QACAA,kBACIA,gCACJA,UAEJA,qCAGIA,8CAAsBK,uDACzBL,YAGTA,yBACIA,oCACAA,wBAQJA,UAGJA,8BAKIA,sCAAcK,oBAAdL,CAAoC,wCACdK,+FAGtBL,oCAIwB,mBAJxBA,CAIwB,mBAJxBA,CAIwB,mBAJxBA,CAIwB,oBAKxBA,iCAqDJA,eAtJiBA,0BAIDA,+DAQIA,uIASmBA,mDAGSA,6DACbA,mDAoBXA,sDAEAA,oEAOyBA,2CAE7BA,gEAIJA,4EAAsD,uDAWzDA,gDASTA,8CAAwB,4CAAxBA,CAAwB,wCAAxBA,CAAwB,0CAAxBA,CAAwB,uCAUpBA,kCAAsB,41CGzDvB,iBAA4CE,MAU/CC,YACcC,EACAC,EACAC,EACAC,EACFC,EACAC,EACAwC,EACAI,GAER3C,MAAMN,EAAOC,EAAQC,EAAqBC,GAThCI,aACAA,cACAA,2BACAA,mBACFA,4BACAA,mBACAA,sBACAA,2BAXZA,6BAAyB,EAChBA,sBAAmB,CAACT,oBAA0BA,qBAanDS,KAAKipB,wBAA0BjpB,KAAKG,qBAAqB,sBACzDH,KAAKkpB,mBAAqBlpB,KAAKG,qBAAqB,iBAGxDC,WACIJ,KAAKmpB,cAAgBnpB,KAAKwH,MAAM8F,SAASnG,KAAKxF,OAAO+B,MACjD,OAAKjE,GAAgCA,EAAQ0a,eAEjDna,KAAKK,WAAa,IAAIJ,KAAU,CAC5Bka,aAAc,IAAIla,KAAU,MAEhCF,MAAMa,OAGVwoB,kBAEI,OAAQppB,KADkBK,WAAWW,IAAI,gBACN+U,SAGvCsT,WAAW5pB,GAEP,OADgBA,EAAYuB,IAAI,WACF+U,SAGlCzW,OACI,GAAIU,KAAKK,WAAWipB,SAAWtpB,KAAKK,WAAWuM,SAC3C,OAGJ,MAAMnN,EAAWO,KAAKmB,YAAYC,QAAQ8X,WAAWlZ,KAAKsB,IAAI6H,UAAUzJ,GAAQA,EAAK0B,YACrFgM,KAAcpN,KAAKkM,QAASlM,KAAK0M,cAAejN,GAC3CiE,MACG,OAAK,MACLqW,KAAS,GAAII,gBAAgBxa,EAAcC,oBACvC,MAAM6C,EAA2C,GACjD,UAAWI,KAAmB7C,KAAKopB,kBAAmB,CAClD,IAA+B,QAA3BvpB,IAAgBmB,IAAI,eAAO,eAAEmM,SAAoC,QAA3BrN,IAAgBkB,IAAI,eAAO,eAAEmM,OAAO,CAC1E,MAAMxE,EAAoBjJ,EAAa2M,KACnCzD,GAAMA,EAAGtH,KAAOuB,EAAgBtB,MAAMD,IAE1C,GAAIqH,EAAmB,CACnB,MAAMC,EAAQ5I,KAAKupB,sBACf5gB,EACA9F,EACAlD,GAEJ8C,EAAiBqK,KACb9M,KAAKmB,YAAYC,QAAQooB,yBAAyB5gB,KAK9D,UAAWD,KAAc3I,KAAKqpB,WAAWxmB,GACrC,IAA0B,QAAtBP,IAAWtB,IAAI,eAAO,eAAEmM,SAA+B,QAAtBzK,IAAW1B,IAAI,eAAO,eAAEmM,OAAO,CAChE,MAAMvE,EAC6C,QAD/BrG,IACf8J,KAAKxD,GAAMA,EAAGvH,KAAOuB,EAAgBtB,MAAMD,WAAG,eAC7CwB,QAAQuJ,KAAKxD,GAAKA,EAAEvH,KAAOqH,EAAWpH,MAAMD,IAClD,GAAIsH,EAAa,CACb,MAAMC,EAAQ7I,KAAKypB,iBACf7gB,EACAD,EACAhJ,GAEJ8C,EAAiBqK,KACb9M,KAAKykB,qBAAqBnJ,oBAAmB3a,+BACpCkI,GAAK,CAAEgS,WAAY7a,KAAK6jB,yBAC7BjkB,EACAD,MAOxB,SAAOkW,KAASpT,MAGvBjB,UACG,KACIxB,KAAKK,WAAWmN,iBAChBxN,KAAK0G,eAAeC,eACpB3G,KAAKyB,oBAAoBC,SAAQ,OAAE,gCAAiC,CAChEC,OAAQ,wBAGhBjC,IACIM,KAAKyB,oBAAoBG,OAAM,OAAE,8BAA+B,CAC5DD,OAAQ,yBAMpB4nB,sBACJ9pB,EACAC,EACAC,GAYA,SAVcJ,OAA0B,CACpC6O,aAAc3O,EACd4O,cAAe3O,EAAqB6B,MACpC+M,kBAAmBtO,KAAKipB,wBACxB1a,eACAC,mBAAoB,CAChBD,eACAjO,KAAMb,EAAYa,MAAQ,MAM9BmpB,iBACJhqB,EACAC,EACAC,GAYA,SAVcJ,OAA0B,CACpC6O,aAAc3O,EACd4O,cAAe3O,EAAgB6B,MAC/B+M,kBAAmBtO,KAAKipB,wBACxB1a,eACAC,mBAAoB,CAChBD,eACAjO,KAAMb,EAAOa,MAAQ,MAMvBuB,cAAcpC,EAA4BC,GAChD,MAAMC,EAAkB,IAAIM,KAAU,IACtC,UAAWL,KAAeH,EAAO0a,aAAc,CAC3C,MAAMta,GAAmB,SAAgBD,EAAaF,GAChDI,EAAQ,CACVwB,GAAI1B,EAAY0B,GAChB8B,UAAWxD,EAAYwD,UACvBsmB,UAAW9pB,EAAY8pB,UACvBpd,KAAM1M,EAAY0M,KAClBhM,KAAMT,EAAmBA,EAAiBS,KAAO,IAE/CgC,EAAmB,IAAIrC,KAAU,IAEvC,UAAWsC,KAAU3C,EAAYkD,QAAS,CACtC,MAAML,KAAoBlD,OAAgBgD,EAAQ7C,GAC5CmD,EAAgB7C,KAAKQ,YAAYC,MAAM,CACzCa,GAAIiB,EAAOjB,GACX8B,UAAWb,EAAOa,UAClBsmB,UAAWnnB,EAAOmnB,UAClBpd,KAAM/J,EAAO+J,KACbhM,KAAMmC,EAAoBA,EAAkBnC,KAAO,KAEvDgC,EAAiBwK,KAAKjK,GAG1B,MAAMH,EAAe1C,KAAKQ,YAAYC,MAAMX,GAC5C4C,EAAawS,WAAW,UAAW5S,GACnC3C,EAAgBmN,KAAKpK,GAEzB1C,KAAKK,WAAWspB,WAAW,eAAgBhqB,2CAnLtCiqB,IAA6BvqB,4HAA7BuqB,GAA6B3nB,qpCDlC1C5C,0BAAgB,gBAAhBA,CAAgB,6BAKJA,8CAAsBK,qDACzBL,UAGLA,wBAAc,UAAdA,CAAc,UAAdA,CAAc,yBAAdA,CAAc,aAQMA,sEAJJA,QAMAA,kBAAOA,gCAA4DA,YAG3EA,4BAQJA,YAGRA,mDA9BYA,0EAAsD,kDAc1CA,mDAEGA,wEAIVA,sDAU4BA,uWEhCzCA,6IAIAA,cAAqCA,SAAsCA,kCAAtCA,mFAGrCA,oBAAkCA,iDAAS4X,WAAU5X,8BAAiCA,QACtFA,oBAAsBA,iDAASwqB,YAC3BxqB,8BACJA,cAHqDA,2CAEjDA,qDCDD,SANPG,cAQIQ,cAA8E,GAE9E6pB,UACI7pB,KAAKuX,aAAY,GAGrBN,SACIjX,KAAKuX,wDCNblY,iBAA0E,UAA1EA,CAA0E,WAE3DA,8BAAkCA,QACzCA,mBAAgBA,qEAAhBA,UAEJA,kBAAoB,WACTA,8BAAyCA,QAChDA,yCAKIA,sDAAOA,EAAPwG,MAAO4Y,qBAAPpf,CAAiC,mDACvBA,EADuBwG,MACvB8V,oBACbtc,UAELA,gBAAK,gBAG+CA,mEAASyqB,uBACrDzqB,wBACJA,wCAnBOA,4CACSA,iCAAwB,qBAGjCA,oDAGHA,mCAAwB,mBAAxBA,CAAwB,wBASxBA,8EAyBIA,gCAAgD,cAGxCA,gFAA6B,sEAGO,IALxCA,QAOAA,iBAAOA,8BAAiCA,4CALpCA,oCAKGA,qFAQPA,+BAA+C,cAIvCA,4EAAyB,6EAIR0qB,wCAPrB1qB,4CAGIA,gCAAyB,mEAOjCA,gBAA+BA,SAAiBA,wCAAjBA,gEAK/BA,+BAA+C,2BAGvCA,8EAA2B,6EAGV0qB,mBACpB1qB,sDAJGA,kCAA2B,0DAMnCA,gBAA+BA,mCAAkDA,kDAAlDA,4FAK/BA,+BAA+C,cAIvCA,8EAA2B,6EAIV0qB,mBAPrB1qB,4CAGIA,6DAORA,gBAA+BA,SAAmBA,wCAAnBA,kEAInCA,wBAAmE,eAE3DA,uBACJA,QACAA,gCAA8C,eAItCA,0EAASA,EAATwG,MAASmkB,6BAGT3qB,uBACAA,8BACJA,kBADIA,8EA3EpBA,cAAsG,WAE9FA,0CAUJA,QACAA,cACIA,8BACJA,QACAA,cAAI,YAEIA,yCAWAA,0BACJA,UAEJA,eAAI,aAEIA,0CASAA,2BACJA,UAEJA,eAAI,aAEIA,0CAWAA,2BACJA,UAEJA,eACIA,mCAgBJA,8CA/E0CA,yCAEfA,mCAYvBA,wDAI0BA,mCAWfA,kCAKeA,mCASfA,kCAKeA,mCAWfA,kCAIIA,kFD3GlB4qB,iCAAqChoB,mQDTlD5C,gCAGAA,8BACAA,cACIA,uBACJA,QACAA,uCAJAA,wFAE4BA,sJGsBrB,SAUHG,YAAYC,GACR,UAAWC,KAAOiB,OAAOolB,KAAKtmB,GAC1BO,KAAKN,GAAOD,EAAOC,IAuBxB,SASHF,YACYC,EACAC,EACAC,EACAC,EACAC,GAJAG,aACAA,mBACAA,4BACAA,2BACAA,oBAbZA,uBAAmB,EACnBA,qBAAiB,EACjBA,uBAAwC,GAcxCI,WACIJ,KAAKkqB,yBACLlqB,KAAKuO,aACAvO,KAAKwH,MAAM8F,SAASrB,SAASjL,IAAI,YAA4BzB,SAClES,KAAKmB,YAAY2W,SAASwG,mBAAmBjT,QAAQ7J,UAAU/B,IAC3DO,KAAKue,aAAe9e,EAAK+e,cAAcD,eAI/CwL,cAActqB,GACVO,KAAKmqB,kBAAmB,EACxB1qB,EAAYmf,SAAU,EAG1BjR,gBACI,OAAQ3N,KAAKmqB,iBAGjBC,mBACI,OAAOpqB,KAAKqqB,kBAAkBpnB,OAAOxD,IAAMA,EAAE6qB,UAAY7qB,EAAEmf,SAG/D2L,eAAe9qB,GACX,OAAkC,IAA3BA,EAAQqD,QAAQhB,UACjBoD,KAAE,2BACFzF,EAAQqD,QAAQF,IAAIlD,GAAKA,EAAEY,MAAMkQ,KAAK,KAGhDga,iBACIxqB,KAAKma,aAAarN,KAAK,CACnB2d,OAAO,EACP5N,QAAQ,EACRvc,KAAM,GACNkM,OAAQ,KAEZxM,KAAK0qB,gBAAiB,EAG1BZ,kBAAkBrqB,GACd,MAAMC,EAAKD,EAAY6B,GACnB7B,EAAYgrB,OACZzqB,KAAKma,aAAena,KAAKma,aAAalX,OAAOtD,GAAMA,IAAOF,GAC1DO,KAAKme,mBACLne,KAAK0qB,gBAAiB,GACfhrB,GACPM,KAAK+E,aACAC,OAAO,CACJC,SAAOC,KAAE,+CACTC,gBAAiB,CAAE7E,KAAMb,EAAYa,MACrC+E,QAAS,CACL,CAAEC,KAAM,YAAaC,SAAOL,KAAE,kBAC9B,CAAEI,KAAM,SAAUC,OAAO,OAAE,iBAAkBC,aAAa,MAGjE9B,QACG+B,KAAU9F,GACFA,EACOK,KAAKmB,YAAYC,QAAQupB,6BAA6B,CACzDzQ,cAAexa,EACfua,UAAWja,KAAKoB,QAAQE,KAGrBoE,MAIlBlE,UAAU,EAAGmpB,yCACsC,YAA5ChrB,EAA6B8E,YAC7BzE,KAAKyB,oBAAoBC,SAAQ,OAAE,gCAAiC,CAChEC,OAAQ,uBAEZ3B,KAAKkqB,yBACLlqB,KAAK0qB,gBAAiB,GAC6B,4BAA5C/qB,EAA6B8E,YACpCzE,KAAKyB,oBAAoBG,MAA0C,QAApChC,IAA6B8E,eAAO,QAAI,MAM3F+Z,UAAUhf,EAAeC,GACrB,MAAMC,EAAQK,KAAKma,aAAa1a,GAC5BE,IACAA,EAAM6M,OAAOM,KAAK,CAAExM,KAAMZ,EAAYmd,QAAQ,IAC9C7c,KAAKme,mBACLne,KAAK0qB,gBAAiB,GAI9B/O,aAAalc,GAAiB6B,KAAIhB,SAC9B,MAAMV,EAAcI,KAAKma,aAAa1a,GAClCG,IACKF,EAIDM,KAAK+E,aACAC,OAAO,CACJC,SAAOC,KAAE,yCACTC,gBAAiB,CAAE7E,QACnB+E,QAAS,CACL,CAAEC,KAAM,YAAaC,SAAOL,KAAE,kBAC9B,CAAEI,KAAM,SAAUC,OAAO,OAAE,iBAAkBC,aAAa,MAGjE9B,MACG,OAAU7D,GACFA,EACOG,KAAKmB,YAAYC,QAAQwpB,oBAAoBlrB,GAE7CgG,MAIlBlE,UAAU,EAAGopB,gCACN/qB,EAAoBiF,SAAWvF,eAC/BS,KAAKyB,oBAAoBC,SAAQ,OAAE,gCAAiC,CAChEC,OAAQ,kBAEZ/B,EAAY4M,OAAS5M,EAAY4M,OAAOvJ,OAAOX,GAAKA,EAAEhB,KAAO5B,GAC7DM,KAAKme,mBACLne,KAAK0qB,gBAAiB,GAEtB1qB,KAAKyB,oBAAoBG,MAAiC,QAA3B9B,IAAoB4E,eAAO,QAAI,OA9B1E9E,EAAY4M,OAAS5M,EAAY4M,OAAOvJ,OAAOpD,GAAKA,EAAES,OAASX,GAC/DK,KAAKme,qBAoCjBA,mBACI,MAAM1e,EAASO,KAAKma,aAAavX,IAAIhD,GAAKA,EAAE4M,QACtC9M,EAAmBM,KAAKqqB,kBACxB1qB,EAA0B,CAC5BC,EACAC,EACAC,EACAwC,qBAEA,MAAMuG,EAAY7I,KAAK6qB,oBAAoBhrB,EAASH,GACpD,OAAO,IAAIorB,GAAiB,CACxBlM,SAAS,EACT0L,WAAYxqB,EACZ6nB,iBAAiC,MAAf7nB,OAAe,EAAfA,EAAiBwB,GACnCypB,YACAjoB,UACA2V,MAAwD,QAAjDlW,EAAsB,QAAtBG,EAAe,MAAf5C,OAAe,EAAfA,EAAiB2Y,aAAK,QAAoB,MAAhBnW,OAAgB,EAAhBA,EAAkBmW,aAAK,QAAI5P,EAAU4P,MACtEgC,IAAkD,QAA7C5X,EAAoB,QAApBJ,EAAe,MAAf3C,OAAe,EAAfA,EAAiB2a,WAAG,QAAoB,MAAhBnY,OAAgB,EAAhBA,EAAkBmY,WAAG,QAAI5R,EAAU4R,IAChEE,MAAoE,QAA7D/R,EAA4B,QAA5BD,EAAe,MAAf7I,OAAe,EAAfA,EAAiB4a,mBAAW,QAAoB,MAAhBpY,OAAgB,EAAhBA,EAAkBoY,mBAAW,QAAI7R,EAAU8R,SAG1F3a,KAAKqqB,kBAAoB5qB,EAAOqC,QAC1B,6BAAwBrC,GAAQmD,IAAIhD,IAChC,MAAMC,EAAkBG,KAAKoB,QAAQgZ,SAAS/N,KAAK/J,GAC/CtC,KAAKgrB,gBAAgB1oB,EAAEQ,QAASlD,IAE9BE,EAAmBE,KAAKoB,QAAQgZ,SAAS/N,KAAK/J,GAChDtC,KAAKirB,iBAAiB3oB,EAAEQ,QAASlD,IAErC,OAAOD,GAAwB,EAAOC,EAASC,EAAiBC,KAEpE,CAACH,GAAwB,EAAM,GAAIK,KAAKoB,QAAQgZ,SAAS,KAO3DyQ,oBACJprB,EACAC,GAKA,OAAIA,EAHgDuD,OAAOrD,GACvDH,EAAQmD,IAAI/C,GAAKA,EAAES,MAAM2C,OAAOpD,GAAQD,EAAEkD,QAAQF,IAAI9C,GAAKA,EAAEQ,MAAM6O,SAAStP,KAEjDiC,UACpBopB,MAAKxrB,EAAiB,GAAI,CAAC,MAAO,QAAS,UAE/C,CACH+a,IAAK,GACLhC,MAAO,EACPkC,MAAO,GAIfqP,cAAcvqB,EAAYC,GACtBM,KAAK+E,aACAC,OAAO,CACJC,SAAOC,KAAE,0CACTC,gBAAiB,CAAE7E,KAAMZ,EAAQkD,IAAIjD,GAAKA,EAAEW,MAAMkQ,KAAK,MACvDnL,QAAS,CACL,CAAEC,KAAM,YAAaC,SAAOL,KAAE,kBAC9B,CAAEI,KAAM,SAAUC,OAAO,OAAE,iBAAkBC,aAAa,MAGjE9B,QACG+B,KAAU9F,GACNA,EAAWK,KAAKykB,qBAAqBlJ,qBAAqB9b,EAAIO,KAAKoB,QAAQE,IAAMoE,QAErFD,KAAU,IAAMzF,KAAKmrB,eAAe,QAEvC3pB,UACG,KACIxB,KAAKyB,oBAAoBC,SAAQ,OAAE,gCAAiC,CAChEC,OAAQ,mBAEZ3B,KAAKkqB,0BAETvqB,IACIK,KAAKyB,oBAAoBG,OAAM,OAAE,8BAA+B,CAC5DD,OAAQ,qBAM5BrC,OACIU,KAAKma,aAAena,KAAKma,aAAalX,OAAOvD,GAAKA,EAAE8M,OAAO1K,QAC3D,MAAMrC,EAAkBO,KAAKma,aACxBlX,OAAOvD,GAAMA,EAAG+qB,OAChB7nB,IAAIlD,IAAO,CACRY,KAAMZ,EAAGY,KACTkM,OAAQ,MAGhBxM,KAAKorB,kBACA1nB,MACG,OAAS,IAAM1D,KAAKqrB,sCACpB,OAAS,IACLrrB,KAAKykB,qBAAqB3K,0BAA0Bra,EAAiBO,KAAKuO,kBAE9EwL,KAASra,GAAuBM,KAAKsrB,yBAAyB5rB,KAC9D,OAASA,GAAuBM,KAAKurB,sBAAsB7rB,KAC3D,OAASA,GAAaM,KAAKwrB,kBAAkB9rB,OAC7Cqa,KAASra,GAAUM,KAAKyrB,yBAAyB/rB,KACjD,OAASA,GAAOM,KAAK0rB,uBAAuBhsB,EAAI6a,2BAChDR,KAASra,GAAYM,KAAKmrB,eAAezrB,KAE5C8B,UAAU,CACPmI,KAAMjK,IACFM,KAAKmqB,kBAAmB,EACxBnqB,KAAKyB,oBAAoBC,SAAQ,OAAE,wCAAyC,CACxEiD,MAAOjF,EAASoC,SAEpB9B,KAAKkqB,yBACLlqB,KAAK0qB,gBAAiB,KAK9BU,kBACJ,MAAM3rB,EAAoBO,KAAKqqB,kBAAkBpnB,OAAO,CAACvD,EAASC,IAE1DD,EAAQkf,SACR5e,KAAKqqB,kBAAkBhe,KAAKzM,GAAMA,EAAG6a,IAAIuD,SAAWte,EAAQ+a,IAAIuD,QAAUpe,IAAOF,IAGzF,OAAID,EAAkBqC,OACX9B,KAAK+E,aACPC,OAAO,CACJC,SAAOC,KAAE,iCACTE,QAAMkB,KAAO7G,EAAkBmD,IAAIlD,GAAK,GAAGA,EAAE+a,QAAQjK,KAAK,MAC1DnL,QAAS,CAAC,CAAEE,OAAO,OAAE,gBAAiBC,aAAa,EAAOF,KAAM,cAEnE5B,QAAKqW,KAASra,GAAOgG,SAEnB6D,OAAG,GAIV8hB,oCACJ,MAAM5rB,EAAmBO,KAAK2rB,sBAC9B,OAAIlsB,EAAiBqC,OACV9B,KAAK+E,aACPqB,cAAc6jB,GAAuC,CAClDnjB,OAAQ,CACJsT,SAAU3a,KAGjBiE,MACG,OAAShE,IACU,IAARA,GAAe,SAAG,GAAQgG,SAItC6D,OAAG,GAIVoiB,sBACJ,OAAO3rB,KAAKoB,QAAQgZ,SAASnX,OACzBxD,IAAYO,KAAKqqB,kBAAkBhe,KAAK3M,GAAMA,EAAGioB,mBAAqBloB,EAAQ6B,KAI9EsqB,sBAAsBnsB,GAC1B,OAAmC,IAA5BA,EAAQ2a,SAAStY,QAAgD,IAAhCrC,EAAQ0a,aAAarY,OAGzDwpB,yBACJ7rB,GAEA,OAAIA,EAAoBqC,UACb+T,KACHpW,EAAoBmD,IAAIlD,GACbM,KAAKmB,YAAYC,QAAQ4Y,wBAAwB,CACpDC,UAAWja,KAAKoB,QAAQE,GACxB4Y,cAAexa,EAAY4B,OAGrCoC,QAAKC,KAAI,IAAMlE,OAEV8J,MAAG,IAIVgiB,sBACJ9rB,GAEA,MAAMC,EAAyCM,KAAKma,aAC/CvX,IAAIhD,IACD,MAAMC,EAAeJ,EAAoB4M,KAAK/J,GAAOA,EAAIhC,OAASV,EAAGU,MAC/DR,EAAuBD,EAAeA,EAAayB,GAAK1B,EAAG0B,GACjE,IAAKxB,EACD,MAAM,IAAIoQ,MAAM,wCAEpB,OAAOtQ,EAAG4M,OACLvJ,OAAOX,IAAMA,EAAEua,QACfja,IAAIN,IAAM,CACPupB,uBACAvf,MAAM,QAAgBhK,EAAEhC,KAAM,KAC9B6V,aAAc,CAAC,CAAE7V,KAAMgC,EAAEhC,KAAMiO,aAAcvO,KAAKuO,oBAG7D7N,OAAO,CAACd,EAAMC,IAAY,IAAID,KAASC,GAAU,IAEhDF,EAAc,IACbF,EAAoBmD,IAAIhD,GAAKA,EAAE0B,OAC/BtB,KAAKma,aAAavX,IAAIhD,GAAKA,EAAE0B,IAAI2B,OAAOqT,uBAG/C,OAAI5W,EAAWoC,UACJ+T,KAASnW,EAAWkD,IAAIhD,GAASI,KAAKmB,YAAYC,QAAQ0qB,iBAAiBlsB,KAAS8D,QACvFC,KAAI,IAAMhE,OAGP4J,MAAG5J,GAIV6rB,kBAAkB/rB,GACtB,SAAOoW,KACHpW,EAAUmD,IAAIlD,GACVM,KAAKmB,YAAYC,QACZ2qB,sBAAsBrsB,GACtByJ,UAAUxJ,GAAQA,EAAKqsB,oBACvBtoB,QAAKyE,MAAOmO,yBAEvB5S,QAAKuoB,MAAe,KAGlBR,yBAAyBhsB,GAC7B,MAAMC,EAAUD,EACXwD,OAAOqT,sBACP1T,IAAIhD,GAAMA,EAAGkD,SACbpC,OAAO,CAACd,EAAMC,IAAM,IAAID,KAASC,GAAI,IACpCF,EAAWK,KAAKqqB,kBACjBpnB,OAAOrD,GAAKA,EAAEgf,UAAYhf,EAAE0qB,UAC5B1nB,IAAIhD,IACD,MAAMC,EAAYJ,EAAOmD,IAAI,CAAC9C,EAAOwC,KACjC,MAAMI,EAAS5C,EAAMgD,QAAQuJ,KAAK9J,GAAKA,EAAEjC,OAASV,EAAEkD,QAAQR,GAAOhC,MACnE,GAAIoC,EACA,OAAOA,EAAOpB,GAEd,MAAM,IAAI4O,MAAM,8CAA8CpQ,EAAMQ,UAG5E,MAAO,CACHmY,MAAO7Y,EAAE6Y,MACTgC,IAAK7a,EAAE6a,IACPE,MAAO/a,EAAE+a,MACTL,eAGZ,OAAOta,KAAKykB,qBAAqBlK,sBAC7Bva,KAAKoB,QACLzB,EACAD,EACAM,KAAKuO,cAILmd,uBAA0BjsB,GAC9B,MAAMC,EAAmBM,KAAK2rB,sBAC9B,GAAIjsB,EAAiBoC,OAAQ,CACzB,MAAMnC,EAAmBD,EAAiBkD,IAAIhD,GAC1CI,KAAKmB,YAAYC,QAAQma,qBAAqB3b,EAAE0B,IAAIoC,MAAK,OAAI,IAAMjE,KAEvE,OAAO,UAAYE,GAEnB,SAAO4J,MAAG9J,GAIV0rB,eAAkB1rB,GAEtB,MAAMC,EAAKM,KAAKwH,MAAM8F,SAASrB,SAASjL,IAAI,MAC5C,OAAItB,EACOM,KAAKmB,YAAYC,QAAQ8X,WAAWxZ,GAAI2L,QAAQ3H,QAAKC,KAAI,IAAMlE,OAE/D8J,MAAG9J,GAIlByqB,yBACIlqB,KAAKmB,YAAYC,QAEZ8qB,0BAA0BlsB,KAAKwH,MAAM8F,SAASrB,SAASjL,IAAI,OAE3DmI,UAAU,EAAG/H,aAAc3B,GAC3B+B,UAAU/B,IACPO,KAAKoB,QAAU3B,EACf,MAAMC,EAAmBD,EAAE2a,SAASxX,IAAIhD,GAAKA,EAAEkD,QAAQF,IAAI/C,GAAUA,EAAOyB,KAAK6qB,OAC3ExsB,EAAwBF,EAAE2a,SAC3BxX,IAAIhD,GAAKA,EAAEkD,QAAQF,IAAI/C,GAAUA,EAAOusB,UACxCD,OACLnsB,KAAKma,aAAe1a,EAAE0a,aAAavX,IAAIhD,IAC5B,CACH0B,GAAI1B,EAAG0B,GACPmpB,OAAO,EACPnqB,KAAMV,EAAGU,KACTuc,OAAQld,EAAsBwP,SAASvP,EAAG0B,IAC1CkL,OAAQ5M,EAAGkD,QAAQF,IAAI/C,IAAM,CACzByB,GAAIzB,EAAEyB,GACNhB,KAAMT,EAAES,KACRuc,OAAQnd,EAAiByP,SAAStP,EAAEyB,UAIhDtB,KAAKme,qBAIT6M,gBAAgBvrB,EAA4BC,GAChD,OAAOM,KAAKqsB,eAAe5sB,KAAOO,KAAKqsB,eAAe3sB,GAGlDurB,iBAAiBxrB,EAA4BC,GACjD,OAAOM,KAAKqsB,eAAe3sB,GAAGyP,SAASnP,KAAKqsB,eAAe5sB,IAGvD4sB,eAAe5sB,GACnB,OAAOA,EACFmD,IAAIlD,GAAKA,EAAEY,MACX6C,OACAqN,KAAK,6CAxdL8b,IAA8BjtB,uFAA9BitB,GAA8BrqB,wrCD9D3C5C,0BAAgB,iBAAhBA,CAAgB,cAIJA,gCAASK,WAGTL,8BACJA,YAIRA,0BAwBAA,oBAA+CA,gCAASK,qBACpDL,sBACAA,8BACJA,QAEAA,kBAA8B,aAA9BA,CAA8B,WAA9BA,CAA8B,SAIdA,eACAA,eAAIA,gCAAmCA,QACvCA,eAAIA,gCAA+BA,QACnCA,eAAIA,gCAAiCA,QACrCA,eAAIA,gCAAyCA,QAC7CA,eACJA,UAEJA,0BAiFJA,iBAjIQA,mGAEAA,sGAKWA,yCA0BnBA,0DAQgBA,+CACAA,2CACAA,6CACAA,qDAIYA,8hBE9CzB,iBAA4BE,MAC/BC,YAAYC,EAAgBC,GACxBK,MACIN,EACA,CACIgF,WAAY,QACZnD,GAAI,GACJ8B,UAAW,GACXsmB,UAAW,GACXppB,KAAM,GACNgF,KAAM/F,YACNgtB,SAAU,EACVC,SAAU,GACVC,MAAO,EACPC,OAAQ,EACRC,OAAQ,GACRC,QAAS,GACTC,WAAY,MAEhBltB,GAAMD,EAAY0B,QAAQ0rB,SAASntB,GAAIwE,UAAUvE,GAAQA,EAAKmH,gDAnB7DgmB,IAAa1tB,sDAAb0tB,GAAapc,QAAboc,GAAa,qBAFV,SCOT,iBAAiCxtB,MACpCC,YAAYC,EAAgBC,GACxBK,MACIN,EACA,CACIgF,WAAY,aACZnD,GAAI,GACJ8B,UAAW,GACXsmB,UAAW,GACXnb,gBAAchP,SACde,KAAM,GACNwK,KAAM,GACNmD,WAAW,EACX+e,YAAa,GACbjiB,YAAa,GACbvE,cAAe,KACfnE,OAAQ,GACR8T,aAAc,GACd7N,gBAAgB,EAChBY,QAAS,GACTiD,OAAQ,GACR4C,SAAU,MAEdpP,GAAMD,EAAYqJ,WAAWkkB,cAActtB,GAAIwE,UAAUvE,GAAQA,EAAKmJ,qDAvBrEmkB,IAAkB7tB,sDAAlB6tB,GAAkBvc,QAAlBuc,GAAkB,qBAFf,SCET,iBAA4B3tB,MAC/BC,YAAYC,EAAgBC,GACxBK,MACIN,EACA,CACIgF,WAAY,QACZnD,GAAI,GACJ8B,UAAW,GACXsmB,UAAW,GACXzb,WAAW,EACXM,gBAAchP,SACde,KAAM,GACNgM,KAAM,GACN6J,aAAc,GACd3J,OAAQ,IAEZ7M,GAAMD,EAAYqV,MAAMW,SAAS/V,GAAIwE,UAAUvE,GAAQA,EAAKmV,gDAhB3DoY,IAAa9tB,sDAAb8tB,GAAaxc,QAAbwc,GAAa,qBAFV,SCET,iBAA8B5tB,MACjCC,YAAYC,EAA0BC,GAClCK,MACIL,EACA,CACI+E,WAAY,UACZnD,GAAI,GACJ8B,UAAW,GACXsmB,UAAW,GACX9K,SAAS,EACTrQ,gBAAchP,SACde,KAAM,GACNwK,KAAM,GACNtE,cAAe,KACfnE,OAAQ,GACR0I,YAAa,GACboL,aAAc,GACdgE,aAAc,GACdyI,YAAa,GACbzJ,YAAa,CAAE/U,MAAO,GAAIN,WAAY,GACtCkU,SAAU,IAEdrY,GACIF,EAAY2B,QACP8X,WAAWvZ,EAAI,CAAEqD,KAAM,KACvBmQ,yBACAhP,UAAUvE,GAAQA,EAAKwB,kDA1B/BgsB,IAAe/tB,sDAAf+tB,GAAezc,QAAfyc,GAAe,qBAFZ,SCDT,iBAAsC7tB,MACzCC,YAAYC,EAAgBC,GACxBK,MACIN,EACA,CACIgF,WAAY,UACZnD,GAAI,GACJ8B,UAAW,GACXsmB,UAAW,GACXppB,KAAM,GACN6Z,aAAc,GACdC,SAAU,IAEdza,GAAMD,EAAY0B,QAAQ8qB,0BAA0BvsB,GAAIwE,UAAUvE,GAAQA,EAAKwB,kDAb9EisB,IAAuBhuB,sDAAvBguB,GAAuB1c,QAAvB0c,GAAuB,qBAFpB,SCsBT,MAAMC,GAAyB,CAClC,CACI/c,KAAM,WACNgd,UAAWvE,GACX7hB,KAAM,CACFqmB,cAAYtoB,KAAE,yBAGtB,CACIqL,KAAM,eACNgd,UAAW1G,GACX4G,WAASluB,OAAkB6tB,IAC3Bzf,cAAe,CAACpO,OAChB4H,KAAM,CACFqmB,WAAYE,KAGpB,CACInd,KAAM,+BACNgd,UAAWjB,GACXmB,WAASluB,OAAkB8tB,IAC3B1f,cAAe,CAACpO,OAChB4H,KAAM,CACFqmB,WAAYG,KAGpB,CACIpd,KAAM,uBACNgd,UAAW3D,GACX6D,WAASluB,OAAkB8tB,IAC3B1f,cAAe,CAACpO,OAChB4H,KAAM,CACFqmB,WAAYI,KAGpB,CACIrd,KAAM,SACNgd,UAAWvW,GACX7P,KAAM,CACFqmB,cAAYtoB,KAAE,uBAGtB,CACIqL,KAAM,aACNgd,UAAWhX,GACXkX,WAASluB,OAAkB4tB,IAC3Bxf,cAAe,CAACpO,OAChB4H,KAAM,CACFqmB,WAAYK,KAGpB,CACItd,KAAM,cACNgd,UAAW9Y,GACXtN,KAAM,CACFqmB,cAAYtoB,KAAE,4BAGtB,CACIqL,KAAM,kBACNgd,UAAW3e,GACX6e,WAASluB,OAAkB2tB,IAC3Bvf,cAAe,CAACpO,OAChB4H,KAAM,CACFqmB,WAAYM,KAGpB,CACIvd,KAAM,SACNgd,UAAW5nB,GACXwB,KAAM,CACFqmB,cAAYtoB,KAAE,uBAGtB,CACIqL,KAAM,aACNgd,UAAWvrB,GACXyrB,WAASluB,OAAkBwtB,IAC3B5lB,KAAM,CACFqmB,WAAYO,MAKjB,YAA2Blf,EAAWpP,GACzC,SAAOF,OAAsE,CACzEoC,OAAQkN,EAAKlN,OACbL,GAAI7B,EAAO6B,GACX0sB,cAAe,sBACfC,QAASvuB,GAAWA,EAAQY,KAC5BkH,MAAO,aAIR,YAAwCqH,EAAWpP,GACtD,OAAOoP,EAAKlN,OAAO+B,MACf,OAAKhE,GACM,CACH,CACI6F,SAAOL,KAAE,uBACTgpB,KAAM,CAAC,MAAO,aAElB,CACI3oB,MAAO,GAAG7F,EAAOY,OACjB4tB,KAAM,CAAC,MAAO,WAAYzuB,EAAO6B,GAAI,CAAEkkB,IAAK,cAEhD,CACIjgB,SAAOL,KAAE,8BACTgpB,KAAM,CAAC,uBAOpB,YAAwCrf,EAAWpP,GACtD,OAAOoP,EAAKlN,OAAO+B,MACf,OAAKhE,GACM,CACH,CACI6F,SAAOL,KAAE,uBACTgpB,KAAM,CAAC,MAAO,aAElB,CACI3oB,MAAO,GAAG7F,EAAOY,OACjB4tB,KAAM,CAAC,MAAO,WAAYzuB,EAAO6B,GAAI,CAAEkkB,IAAK,cAEhD,CACIjgB,SAAOL,KAAE,8BACTgpB,KAAM,CAAC,eAOpB,YAAyBrf,EAAWpP,GACvC,SAAOF,OAA0C,CAC7CoC,OAAQkN,EAAKlN,OACbL,GAAI7B,EAAO6B,GACX0sB,cAAe,oBACfC,QAASvuB,GAASA,EAAMY,KACxBkH,MAAO,WAIR,YAA8BqH,EAAWpP,GAC5C,SAAOF,OAAqC,CACxCoC,OAAQkN,EAAKlN,OACbL,GAAI7B,EAAO6B,GACX0sB,cAAe,yBACfC,QAASvuB,GAAcA,EAAWY,KAClCkH,MAAO,gBAIR,YAAyBqH,EAAWpP,GACvC,SAAOF,OAAgC,CACnCoC,OAAQkN,EAAKlN,OACbL,GAAI7B,EAAO6B,GACX0sB,cAAe,oBACfC,QAASvuB,GAASA,EAAMY,KACxBkH,MAAO,kCC9LXnI,iKAgBQA,yMAGAA,qIANRA,oBAAkCA,iDAAS4X,WAAU5X,8BAAiCA,QACtFA,oBAAsBA,iDAASqY,WAC3BrY,gCAGAA,2CAGJA,2CARqDA,2CACZA,8CACxBA,yCAAwB,eCHtC,SASHG,YAAoBC,EAAkCC,GAAlCM,mBAAkCA,2BAJtDA,8BAA2B,IAAIC,KAM/BG,WACI,MAAMX,EAAmBO,KAAKmB,YAAYiQ,OACrCC,aACAlI,UAAU,EAAGkI,gBAAiB1R,EAAWkY,iBACxCnY,EAAeM,KAAKmB,YAAY2W,SAASC,cAAc5O,UAAUxJ,GAAQA,EAAKqY,aAEpF5K,KAAc3N,EAAkBC,GAAc8B,UAAU,EAAE7B,EAAiBC,MAEvEI,KAAKiY,eAAiBrY,EAASyM,KAAKxM,GAAKA,EAAEyB,KAAO3B,GAClDK,KAAKkY,kBAAoBtY,IAG7BI,KAAKmY,yBAAyBtQ,aAAarG,UAAU7B,IACjDK,KAAKoY,cAAczY,KAI3ByY,cAAc3Y,GACVO,KAAK2Y,gBAAkB3Y,KAAKkY,kBAAkB7L,KAAK3M,GAAKA,EAAE4B,KAAO7B,EAAW,IAGhFiY,SACI,MAAMjY,EAAkBO,KAAK2Y,gBACzBlZ,GACAO,KAAKuX,YAAY9X,GAIzBwX,SACIjX,KAAKuX,sDAxCA6K,IAA8B/iB,qDAA9B+iB,GAA8BngB,uWDb3C5C,gCAGAA,iCAAiC,WACtBA,8BAAkCA,QACzCA,4CAMJA,QAEAA,uCATWA,4CAGHA,8BAAkB,2BAAlBA,CAAkB,sOELnB,MAAM8uB,GAAwCC;;;;;;;;;;;;;;;;;;;EAqBxCC,GAAwCD;;;;;;;;;;;;;;;;;;;;EAsBxCE,GAAuBF;;;;;;;;;;;;EAcvBG,GAAuBH;;;;;;;;;;;;yBC1DhC/uB,qHAmBYA,kBAAkCA,SAAcA,wCAAdA,gEAGlCA,mCAGIA,gFAAUA,EAAVwG,OAAUgb,2BACbxhB,oCAFGA,iDARZA,cAA+B,UAA/BA,CAA+B,SAElBA,SAAeA,QACpBA,yBACJA,QACAA,iBACIA,0CAKJA,oCATSA,uBACCA,6BAIqBA,mEAT3CA,mBAAmE,WAE3DA,uBAaJA,gCAbyBA,0DAiBzBA,kBACAA,uBACAA,kDAIAA,qBAAkCA,iDAAS4X,WAAU5X,8BAAiCA,QACtFA,qBAEIA,iDAASmvB,mBAITnvB,8BACJA,gCARqDA,2CAIjDA,kFAGAA,oDCDD,SAaHG,YAAoBC,EAAkCC,GAAlCM,mBAAkCA,yBARtDA,UAA8B,UAE9BA,WAAwC,UAExCA,oBAA4C,GAC5CA,WAA4B,GAC5BA,yBAAqB,EAIrBI,mBACI,MAAMT,EACY,YAAdK,KAAKyuB,KACCzuB,KAAKmB,YACAutB,MAGCP,GAAuC,CACrCQ,IAAa,QAARlvB,OAAKkvB,WAAG,QAAI,KAEpBxlB,UAAU,EAAGylB,cACVhvB,EAASwE,MAAMxB,IAAI/C,GAAKc,+BAAMd,GAAC,CAAE+iB,YAAa,IAAI/iB,EAAE+iB,iBAE5D5iB,KAAKmB,YACAutB,MAGCL,GAAuC,CACrCM,IAAa,QAARjvB,OAAKivB,WAAG,QAAI,KAEpBxlB,UAAU,EAAGG,qBACV1J,EAAgBwE,MAAMxB,IAAI/C,GAAKc,+BAAMd,GAAC,CAAE+iB,YAAa,IAAI/iB,EAAE+iB,iBAE7E5iB,KAAK0R,aAAe/R,EAAW6B,UAAU,CACrCmI,KAAM/J,IACFI,KAAKoE,MAAQxE,EACbI,KAAKyoB,MAAQ,QACbzoB,KAAK4R,kBAAkBjL,kBAKnC9F,oBACqB,QAAjBpB,OAAKiS,oBAAY,SAAEK,cAGvBkF,SACIjX,KAAKuX,cAGTsJ,iBAAiBphB,EAAwBC,GACrCD,EAAKmjB,YAAcnjB,EAAKmjB,YAAY3f,OAAOtD,GAAMA,EAAG2B,KAAO5B,GAC3DM,KAAK6uB,oBAAqB,EAG9BL,yBACI,MAAM7uB,EAAwBK,KAAKwX,eAAe5U,IAAI/C,GAAMA,EAAGyB,IAC/D,YAAKmnB,MAAQ,UAEK,YAAdzoB,KAAKyuB,KACCzuB,KAAKmB,YAAY2tB,OACbR,GACA,CACI3Q,MAAiB,QAAVle,OAAK2E,aAAK,eAAExB,IAAI/C,IAAY,CAC/ByB,GAAIzB,EAAQyB,GACZuhB,iBAAevc,KAAO,IACfzG,EAAQ+iB,YAAYhgB,IAAI9C,GAAMA,EAAGwB,OACjC3B,SAKnBK,KAAKmB,YAAY2tB,OACbP,GACA,CACI5Q,MAAiB,QAAVje,OAAK0E,aAAK,eAAExB,IAAI/C,IAAY,CAC/ByB,GAAIzB,EAAQyB,GACZuhB,iBAAevc,KAAO,IACfzG,EAAQ+iB,YAAYhgB,IAAI9C,GAAMA,EAAGwB,OACjC3B,UAKhB6B,UAAU3B,IACnBG,KAAKuX,YAAYvX,KAAKwX,0DA1FrBuX,IAAiC1vB,qDAAjC0vB,GAAiC9sB,sjBD9C9C5C,gCAIAA,iBAAkB,UAAlBA,CAAkB,WAGNA,8BACJA,QACAA,sCACIA,qEACHA,YAITA,0BAkBAA,2CAMAA,wDAhCYA,6DAQUA,2CAA2B,qQEM1C,MAAM2vB,GAAsF,CAC/F3J,SAAU,kBACV9f,SAAOL,KAAE,iBACT+pB,KAAM,QACNC,UAAW,YACXC,mBAAoBtgB,GAChBA,EAAgBM,SAAS5P,yBACzBsP,EAAgBM,SAAS5P,qBAC7B6vB,QAAS,EAAGC,WAAUC,YAAWC,gBAAeC,qBAC5C,MAAM5vB,EAAeiP,EAAS7N,IAAIzB,OAC5BM,EAAcgP,EAAS7N,IAAIzB,OAC3BO,EAAsB+O,EAAS7N,IAAIzB,OAEzCK,EACKoF,OAAO,CACJC,SAAOC,KAAE,2CACTC,gBAAiB,CACbR,MAAOlF,EAAUqC,QAErBuD,QAAS,CACL,CAAEC,KAAM,YAAaC,SAAOL,KAAE,kBAC9B,CAAEI,KAAM,SAAUC,OAAO,OAAE,iBAAkBC,aAAa,MAGjE9B,QACG+B,KAAUnD,GACNA,EACMzC,EAAYkJ,WAAW0mB,mBAAkB,OAAOhwB,EAAUmD,IAAIF,GAAKA,EAAEpB,MACrEoE,MAGblE,UAAUc,IACP,IAAII,EAAU,EACd,MAAMH,EAAmB,GACzB,UAAWE,KAAQH,EAAOmtB,kBAClBhtB,EAAKqC,SAAWvF,cAChBmD,IACOD,EAAKiC,SACZnC,EAAOuK,KAAKrK,EAAKiC,SAGrB,EAAIhC,GACJ5C,EAAoB4B,SAAQ,OAAE,kDAAmD,CAC7EiD,MAAOjC,IAGX,EAAIH,EAAOT,QACXhC,EAAoB8B,MAAMW,EAAOiO,KAAK,OAE1C9Q,EAAcsE,UACdrE,QAKH+vB,GAA+F,CACxGrK,SAAU,kBACV9f,SAAOL,KAAE,6BACT+pB,KAAM,SACNE,mBAAoBtgB,GAChBA,EAAgBM,SAAS5P,sBACzBsP,EAAgBM,SAAS5P,qBAC7BowB,UAAW,EAAGN,eAAe,SAAexgB,EAAS7N,IAAIzB,QACzD6vB,QAAS,EAAGC,WAAUC,YAAWC,gBAAeC,qBAC5C,MAAM5vB,EAAeiP,EAAS7N,IAAIzB,OAC5BM,EAAcgP,EAAS7N,IAAIzB,OAC3BO,EAAsB+O,EAAS7N,IAAIzB,OACzCK,EACKwG,cAAcgc,GAAgC,CAC3C/b,KAAM,KACNS,OAAQ,KAEXpD,QACG+B,KAAUnD,GACFA,EACOzC,EAAYkJ,WACd6mB,2BAA2B,CACxBC,cAAepwB,EAAUmD,IAAIF,GAAKA,EAAEpB,IACpCuX,UAAWvW,EAAOhB,KAErBoC,QAAKosB,MAAMxtB,IAEToD,MAIlBlE,UAAUc,IACPxC,EAAoB4B,SAAQ,OAAE,iDAAkD,CAC5EiD,MAAOlF,EAAUqC,OACjB4jB,YAAapjB,EAAOgK,OAExB3M,QAKHowB,GACT,CACI1K,SAAU,kBACV9f,SAAOL,KAAE,+BACTiqB,mBAAoBtgB,GAChBA,EAAgBM,SAAS5P,sBACzBsP,EAAgBM,SAAS5P,qBAC7BywB,mBAAoB,EAAGX,eAAe,SAA6BxgB,EAAS7N,IAAIzB,QAChF0vB,KAAM,SACNC,UAAW,aACXS,UAAW,EAAGN,eAAe,SAA2BxgB,EAAS7N,IAAIzB,QACrE6vB,QAAS,EAAGC,WAAUC,YAAWC,gBAAeC,qBAC5C,MAAM5vB,EAAeiP,EAAS7N,IAAIzB,OAC5BM,EAAcgP,EAAS7N,IAAIzB,OAC3BO,EAAsB+O,EAAS7N,IAAIzB,OACnC+C,EAAmBzC,EAAYuR,OAChCC,aACAlI,UAAU,EAAGkI,gBAAiB3O,EAAWmV,oBAE9CS,OAAK,SAA6BzJ,EAAS7N,IAAIzB,SAC1CmE,QACG+B,KAAU,EAAGigB,iBACT9lB,EAAaoF,OAAO,CAChBC,SAAOC,KAAE,+BACTC,gBAAiB,CACbugB,eAEJrgB,QAAS,CACL,CAAEC,KAAM,YAAaC,SAAOL,KAAE,kBAC9B,CACII,KAAM,SACNC,SAAOL,KAAE,iBACTM,aAAa,QAK7B,OAAU9C,GACNA,EACMJ,EAAiBoB,QACb+B,KAAUlD,GACNA,EACM1C,EAAYkJ,WAAWknB,6BAA6B,CAChDpX,UAAWtW,EACXstB,cAAepwB,EAAUmD,IAAIH,GAAKA,EAAEnB,MAExCoE,QAEVoqB,OAAM,KAEV,SAAG,KAGhBtuB,UAAUkB,IACHA,IACA/C,IACAG,EAAoB4B,SAChB,OAAE,0DACF,CACIiD,MAAOlF,EAAUqC,SAGzBpC,EAAcsE,eC7JzBksB,GAA8F,CACvG7K,SAAU,aACV9f,SAAOL,KAAE,iBACT+pB,KAAM,QACNC,UAAW,YACXC,mBAAoBtgB,GAChBA,EAAgBM,SAAS5P,oBACzBsP,EAAgBM,SAAS5P,qBAC7B6vB,QAAS,EAAGC,WAAUC,YAAWC,gBAAeC,qBAC5C,MAAM5vB,EAAeiP,EAAS7N,IAAIzB,OAC5BM,EAAcgP,EAAS7N,IAAIzB,OAC3BO,EAAsB+O,EAAS7N,IAAIzB,OAEzC,WAA4BmD,EAAoBH,GAC5C,OAAO3C,EACFoF,OAAO,CACJC,SAAOC,KAAE,sCACTC,gBAAiB,CACbR,MAAOlF,EAAUqC,QAErBuE,KAAM9D,EAAU,KAAO,KACvB6C,KAAM7C,EACN8C,QAAS,CACL,CAAEC,KAAM,YAAaC,SAAOL,KAAE,kBAC9B,CACII,KAAM,SACNC,MAAOhD,KAAU2C,KAAE,0BAAyBA,KAAE,iBAC9CM,aAAa,MAIxB9B,QACG+B,KAAUhD,GACNA,EACM5C,EAAYkV,MACPob,aAAaztB,IAAYH,GACzBmB,QAAKC,KAAId,GAAQA,EAAKstB,kBAC3B5mB,MAAG,MAKzBjH,GAAmB,OAAO7C,EAAUmD,IAAIF,GAAKA,EAAEpB,MAC1CoC,MACG,OAAUhB,UACN,IAAID,EAAe,EACnB,MAAMI,EAAmB,GACnB8F,EAAqB,GAC3B,IAAIC,EAAI,EACR,UAAWC,KAAQnG,EACXmG,EAAK/D,SAAWvF,cAChBkD,IACOoG,EAAKnE,UACZ7B,EAAOiK,KAAKjE,EAAKnE,SACjBiE,EAASmE,KAAiB,QAAZvK,IAAUqG,UAAE,eAAEtH,KAEhCsH,IAEJ,OAAI,EAAID,EAAS7G,OACNQ,EAAmBqG,EAAU9F,EAAO2N,KAAK,OAAO9M,MACnD,OAAImF,IACA,MAAMC,EAAgBD,EAAQ5F,OAC1BmG,GAAKA,EAAEtE,SAAWvF,eACpBuC,OACF,OAAOW,EAAeqG,QAIvBS,MAAG9G,MAIrBjB,UAAUkB,IACHA,IACAhD,EAAcsE,UACdrE,IACAG,EAAoB4B,SAAQ,OAAE,6CAA8C,CACxEiD,MAAOjC,SAOlB0tB,GAGT,CACA/K,SAAU,aACV9f,SAAOL,KAAE,6BACT+pB,KAAM,SACNE,mBAAoBtgB,GAChBA,EAAgBM,SAAS5P,oBACzBsP,EAAgBM,SAAS5P,qBAC7BowB,UAAW,EAAGN,eAAe,SAAexgB,EAAS7N,IAAIzB,QACzD6vB,QAAS,EAAGC,WAAUC,YAAWC,gBAAeC,qBAC5C,MAAM5vB,EAAeiP,EAAS7N,IAAIzB,OAC5BM,EAAcgP,EAAS7N,IAAIzB,OAC3BO,EAAsB+O,EAAS7N,IAAIzB,OACzCK,EACKwG,cAAcgc,GAAgC,CAC3C/b,KAAM,KACNS,OAAQ,KAEXpD,QACG+B,KAAUnD,GACFA,EACOzC,EAAYkV,MACdsb,sBAAsB,CACnBC,SAAU7wB,EAAUmD,IAAIF,GAAKA,EAAEpB,IAC/BuX,UAAWvW,EAAOhB,KAErBoC,QAAKosB,MAAMxtB,IAEToD,MAIlBlE,UAAUc,IACPxC,EAAoB4B,SAAQ,OAAE,4CAA6C,CACvEiD,MAAOlF,EAAUqC,OACjB4jB,YAAapjB,EAAOgK,OAExB3M,QAKH4wB,GAGT,CACAlL,SAAU,aACV9f,SAAOL,KAAE,+BACT8qB,mBAAoB,EAAGX,eAAe,SAA6BxgB,EAAS7N,IAAIzB,QAChF0vB,KAAM,SACNC,UAAW,aACXC,mBAAoBtgB,GAChBA,EAAgBM,SAAS5P,oBACzBsP,EAAgBM,SAAS5P,qBAC7BowB,UAAW,EAAGN,eAAe,SAA2BxgB,EAAS7N,IAAIzB,QACrE6vB,QAAS,EAAGC,WAAUC,YAAWC,gBAAeC,qBAC5C,MAAM5vB,EAAeiP,EAAS7N,IAAIzB,OAC5BM,EAAcgP,EAAS7N,IAAIzB,OAC3BO,EAAsB+O,EAAS7N,IAAIzB,OAEnC+C,EAAmBzC,EAAYuR,OAChCC,aACAlI,UAAU,EAAGkI,gBAAiB9O,EAAWsV,iBAE9C,WAA4BtV,EAAoBE,GAC5C,OAAO7C,EACFoF,OAAO,CACJC,SAAOC,KAAE,+BACTC,gBAAiB,CACbR,MAAOlF,EAAUqC,QAErBuE,KAAM5D,EAAU,KAAO,KACvB2C,KAAM3C,EACN4C,QAAS,CACL,CAAEC,KAAM,YAAaC,SAAOL,KAAE,kBAC9B,CACII,KAAM,SACNC,MAAO9C,KAAUyC,KAAE,0BAAyBA,KAAE,iBAC9CM,aAAa,MAIxB9B,MACG,OAAUb,GACNA,EACMP,EAAiBoB,QACb+B,KAAUkD,GACNA,EACM9I,EAAYkV,MAAMyb,wBAAwB,CACtC3X,UAAWlQ,EACX2nB,WACAG,QAAShuB,IAEbiD,MAEV,OAAIiD,GAAQA,EAAK6nB,0BAErB9qB,MAKtBhD,GAAmB,OAAOjD,EAAUmD,IAAIL,GAAKA,EAAEjB,MAC1CoC,MACG,OAAUnB,UACN,IAAIM,EAAepD,EAAUqC,OAC7B,MAAM6G,EAAmB,GACnBC,EAAqB,GAC3B,IAAIC,EAAI,EACR,UAAWC,KAAQvG,EACS,oBAApBuG,EAAKrE,aACLkE,EAAOmE,KAAKhE,EAAKpE,SACjBkE,EAASkE,KAAiB,QAAZrK,IAAUoG,UAAE,eAAEvH,IAC5BuB,KAEJgG,IAEJ,OAAI,EAAID,EAAS9G,OACNY,EAAmBkG,EAAUD,EAAO6H,KAAK,OAAO9M,MACnD,OAAIoF,IACA,MAAMM,EAAkBN,EAAQ7F,OAC5B+S,GAAsB,oBAAjBA,EAAEvR,YACT3C,OACF,OAAOrC,EAAUqC,OAASsH,QAI3BG,MAAG1G,MAGlB,OAAUN,GACNA,KACMhD,OAA6BM,GAAa6wB,KAAK,EAAGhL,kBAAmB,CACjEA,cACAiL,kBAEJjrB,MAGblE,UAAU,EAAGmvB,eAAcjL,kBACpBnjB,IACA7C,EAAcsE,UACdrE,IACAG,EAAoB4B,SAAQ,OAAE,qDAAsD,CAChFiD,MAAOpC,EACPmjB,qBCxOXkL,GAAyE,CAClFvL,SAAU,eACV9f,SAAOL,KAAE,iBACT+pB,KAAM,QACNC,UAAW,YACXC,mBAAoBtgB,GAChBA,EAAgBM,SAAS5P,sBACzBsP,EAAgBM,SAAS5P,qBAC7B6vB,QAAS,EAAGC,WAAUC,YAAWC,gBAAeC,qBAC5C,MAAM5vB,EAAeiP,EAAS7N,IAAIzB,OAC5BM,EAAcgP,EAAS7N,IAAIzB,OAC3BO,EAAsB+O,EAAS7N,IAAIzB,OACzCK,EACKoF,OAAO,CACJC,SAAOC,KAAE,wCACTC,gBAAiB,CACbR,MAAOlF,EAAUqC,QAErBuD,QAAS,CACL,CAAEC,KAAM,YAAaC,SAAOL,KAAE,kBAC9B,CAAEI,KAAM,SAAUC,OAAO,OAAE,iBAAkBC,aAAa,MAGjE9B,QACG+B,KAAUnD,GACNA,EACMzC,EAAYuB,QAAQyvB,gBAAe,OAAOpxB,EAAUmD,IAAIF,GAAKA,EAAEuX,aAC/DvU,MAGblE,UAAUc,IACP,IAAII,EAAU,EACd,MAAMH,EAAmB,GACzB,UAAWE,KAAQH,EAAOuuB,eAClBpuB,EAAKqC,SAAWvF,cAChBmD,IACOD,EAAKiC,SACZnC,EAAOuK,KAAKrK,EAAKiC,SAGrB,EAAIhC,GACJ5C,EAAoB4B,SAAQ,OAAE,+CAAgD,CAC1EiD,MAAOjC,IAGX,EAAIH,EAAOT,QACXhC,EAAoB8B,MAAMW,EAAOiO,KAAK,OAE1C9Q,EAAcsE,UACdrE,QAKHmxB,GAAkF,CAC3FzL,SAAU,eACV9f,SAAOL,KAAE,6BACT+pB,KAAM,SACNE,mBAAoBtgB,GAChBA,EAAgBM,SAAS5P,sBACzBsP,EAAgBM,SAAS5P,qBAC7BowB,UAAW,EAAGN,eAAe,SAAexgB,EAAS7N,IAAIzB,QACzD6vB,QAAS,EAAGC,WAAUC,YAAWC,gBAAeC,qBAC5C,MAAM5vB,EAAeiP,EAAS7N,IAAIzB,OACdsP,EAAS7N,IAAIzB,OACLsP,EAAS7N,IAAIzB,OACzCK,EACKwG,cAAciT,EAAwC,CACnDhT,KAAM,KACNS,OAAQ,CACJmS,YAAY,OAAOxZ,EAAUmD,IAAIN,GAAKA,EAAE2X,YACxCwL,kBAAmB,MAG1BjkB,UAAUc,IACHA,GACA3C,QAMPoxB,GAAoF,CAC7F1L,SAAU,eACV9f,SAAOL,KAAE,+BACTiqB,mBAAoBtgB,GAChBA,EAAgBM,SAAS5P,sBACzBsP,EAAgBM,SAAS5P,qBAC7BywB,mBAAoB,EAAGX,eAAe,SAA6BxgB,EAAS7N,IAAIzB,QAChF0vB,KAAM,SACNC,UAAW,aACXS,UAAW,EAAGN,eAAe,SAA2BxgB,EAAS7N,IAAIzB,QACrE6vB,QAAS,EAAGC,WAAUC,YAAWC,gBAAeC,qBAC5C,MAAM5vB,EAAeiP,EAAS7N,IAAIzB,OAC5BM,EAAcgP,EAAS7N,IAAIzB,OAC3BO,EAAsB+O,EAAS7N,IAAIzB,OACnC+C,EAAmBzC,EAAYuR,OAChCC,aACAlI,UAAU,EAAGkI,gBAAiB3O,EAAWmV,oBAE9CS,OAAK,SAA6BzJ,EAAS7N,IAAIzB,SAC1CmE,QACG+B,KAAU,EAAGigB,iBACT9lB,EAAaoF,OAAO,CAChBC,SAAOC,KAAE,+BACTC,gBAAiB,CACbugB,eAEJrgB,QAAS,CACL,CAAEC,KAAM,YAAaC,SAAOL,KAAE,kBAC9B,CACII,KAAM,SACNC,SAAOL,KAAE,iBACTM,aAAa,QAK7B,OAAU9C,GACNA,EACMJ,EAAiBoB,QACb+B,KAAUlD,GACNA,EACM1C,EAAYuB,QAAQukB,0BAA0B,CAC1C9M,UAAWtW,EACX0W,WAAYxZ,EAAUmD,IAAIH,GAAKA,EAAEwX,aAErCvU,QAEVoqB,OAAM,KAEV,SAAG,KAGhBtuB,UAAUkB,IACHA,IACA/C,IACAG,EAAoB4B,SAAQ,OAAE,sDAAuD,CACjFiD,MAAOlF,EAAUqC,SAErBsV,WAAW,IAAM1X,EAAcsE,UAAW,UAMjDgtB,GAAsF,CAC/F3L,SAAU,eACV9f,SAAOL,KAAE,6BACT+pB,KAAM,MACNE,mBAAoBtgB,GAChBA,EAAgBM,SAAS5P,sBACzBsP,EAAgBM,SAAS5P,qBAC7B6vB,QAAS,EAAGC,WAAUC,YAAWC,gBAAeC,qBAC5C,MAAM5vB,EAAeiP,EAAS7N,IAAIzB,OAE5BO,GADc+O,EAAS7N,IAAIzB,OACLsP,EAAS7N,IAAIzB,QACnC+C,EAA8B5C,EAAcgoB,eAAiB,UAAY,UACzEhlB,EACO,YAATJ,GACM,OAAO7C,EAAUmD,IAAIL,GAAKA,EAAE0X,aAC5B,OAAOxa,EAAUmD,IAAIL,GAAKA,EAAEolB,mBACtC,OAAO/nB,EACFwG,cAAc2oB,GAAmC,CAC9C1oB,KAAM,KACNS,OAAQ,CACJ2nB,OACAE,SAGPntB,UAAUe,IACHA,IACAzC,EAAoB4B,SAAQ,OAAE,qCAAsC,CAChEiD,MAAOlF,EAAUqC,OACjBH,OAAiB,YAATW,EAAqB,WAAa,oBAE9C3C,SCrHb,SACHH,YAAoBC,oCAChBA,EAA0BwxB,mBAAmBD,IAC7CvxB,EAA0BwxB,mBAAmBH,IAC7CrxB,EAA0BwxB,mBAAmBF,IAC7CtxB,EAA0BwxB,mBAAmBL,IAE7CnxB,EAA0BwxB,mBAAmBb,IAC7C3wB,EAA0BwxB,mBAAmBV,IAC7C9wB,EAA0BwxB,mBAAmBf,IAE7CzwB,EAA0BwxB,mBAAmBvB,IAC7CjwB,EAA0BwxB,mBAAmBlB,IAC7CtwB,EAA0BwxB,mBAAmBjC,4CAbxCkC,IAAa7xB,wCAAb6xB,kCAJA,CAAC3xB,MAAc4xB,cAAsB7D","names":["t","save","c","constructor","n","e","o","a","r","s","super","this","p","customFields","getCustomFieldConfig","ngOnInit","detailForm","name","tags","formBuilder","group","reduce","Object","init","ngOnDestroy","destroy","onAssetChange","get","setValue","markAsDirty","dataService","product","updateAsset","id","value","subscribe","notificationService","success","entity","error","setFormValues","length","setCustomFieldFormValues","rt","selectors","U","setQueryFn","getAssetList","assets","d","m","searchTerm$","_","l","filterByTags$","map","f","options","skip","take","filter","contains","sort","createdAt","tagsOperator","paginationConfig$","itemsPerPage$","currentPage$","totalItems$","pipe","C","itemsPerPage","currentPage","totalItems","destroy$","refresh","allTags$","getTagList","mapStream","items","filesSelected","uploading","createAssets","ue","__typename","message","count","deleteAssets","showModalAndDelete","result","modalService","dialog","title","u","translationVars","body","buttons","type","label","returnValue","b","M","st","selectAssets","oxw","dropListDropped","previewAsset","setAsFeatured","removeAsset","assetsSetter","slice","fromComponent","size","J","concat","featuredAsset","emitChangeEvent","changeDetector","markForCheck","isFeatured","closable","locals","asset","change","emit","previousContainer","data","container","j","$t","contentsCurrentPage$","route","queryParamMap","contentsItemsPerPage$","Y","filterTermControl","valueChanges","q","setContentsPageNumber","mt","filterChanges$","asObservable","Qt","previewUpdatedFilters","inheritFiltersChanges$","inheritFilters","collectionIdChange$","parentIdChange$","refresh$","isLoading","v","Z","T","y","collection","previewCollectionVariants","parentId","filters","mapSingle","L","getCollectionContents","productVariants","k","contents$","contentsTotalItems$","ngOnChanges","next","collectionId","currentValue","updatedFilters","complete","setParam","setContentsItemsPerPage","router","navigate","relativeTo","queryParams","queryParamsHandling","replaceUrl","nt","create","removeFilter","addFilter","toggleLivePreview","updateSlug","slug","description","visible","array","livePreview","localStorageService","getCollectionFilters","single$","allFilters","collectionFilters","inheritFilters$","updatedFilters$","statusChanges","filterRemoved$","$","touched","mapOperationsToInputs","arguments","parentId$","paramMap","entity$","parent","getFilterDefinition","find","code","assetsChanged","values","assetChanges","languageCode$","w","pristine","args","push","control","removeAt","markAsTouched","splice","dirty","I","getUpdatedCollection","snapshot","createCollection","markAsPristine","updateCollection","contentsComponent","canDeactivate","set","trackByFn","JSON","stringify","patchValue","isPrivate","clear","forEach","translatable","updatedFields","customFieldConfig","languageCode","defaultTranslation","assetIds","featuredAssetId","entries","gt","i","Map","children","Xn","hasOwnProperty","expanded","includes","rearrange$","_rearrange$","delete$","_delete$","setCollectionTree","collectionTree","resetMoveList","allMoveListItems","getMoveListItems","calculateAllMoveListItems","ancestorIdPath","has","onDrop","item","Error","index","currentIndex","onMove","onDelete","path","join","Set","B","factory","toggleExpanded","move","selectionManager","moveUp","moveDown","delete","depth","parentName","client","userStatus","permissions","_t","hasUpdatePermission$","hasDeletePermission$","subscription","selectionChanges$","changeDetectorRef","expandAll","previousValue","unsubscribe","split","moveListItems","collectionTreeService","drop","previousIndex","H","pipes","collections","he","expandedIds","rearrange","deleteCollection","ht","closeContents","additiveMode","multiSelect","itemsAreEqual","queryResult","getCollections","refetchOnChannelChange","items$","setCurrentItems","activeCollectionId$","activeCollectionTitle$","availableLanguages$","serverConfigService","getAvailableLanguages","contentLanguage$","uiState","contentLanguage","completed$","toggleExpandAll","onRearrange","moveCollection","findIndex","params","contents","setLanguage","setContentLanguage","ref","refetch","ft","updateValueCode","deleteFacetValue","addFacetValue","updateCode","customValueFields","facet","customValueFieldIsSet","getValuesFormArray","addControl","insert","getUpdatedFacet","createFacet","getAllFacets","updateFacet","getCreatedFacetValues","createFacetValues","getFacet","getUpdatedFacetValues","updateFacetValues","E","deleteFacetValues","controls","S","Wt","Jt","translations","facetId","toString","R","vt","toggleDisplayLimit","deleteFacet","getFacets","facets","So","Q","displayLimit","initialLimit","Ct","cancel","selectValues","ngAfterViewInit","setTimeout","selector","focus","resolveWith","selectedValues","ot","assign","isProductVariantMode","productVariantIds","activeChannelId","settings","getChannels","channels","currentChannel","availableChannels","selectedChannelIdControl","selectChannel","variantsPreview$","jt","getTopVariants","priceFactorControl","price","pricePreview","selectedChannel","assignVariantsToChannel","channelId","priceFactor","channel","assignProductsToChannel","productIds","getProduct","variantList","toPromise","z","lastIndexOf","substr","replace","getTaxCategories","taxCategories","createProductWithVariants","createProduct","groups","createProductOptionGroups","F","addOptionGroupToProduct","productId","optionGroupId","optionGroups","variants","optionValues","optionIds","createProductVariants","createProductOptionGroup","sku","stockOnHand","stock","updateProduct","autoUpdate","productInput","variantsInput","getProductVariants","tn","de","Bt","ce","updateProductVariants","updateProductOption","deleteProductVariant","xi","bi","K","removeOption","updateOption","editName","Oe","provide","useExisting","W","multi","formValue","registerOnChange","onChangeFn","registerOnTouched","onTouchFn","setDisabledState","disabled","writeValue","textArea","nativeElement","locked","cancelBubble","editingIndex","nameInputs","target","edit","option","remove","handleKey","key","addOptionValue","preventDefault","lastSelected","removeLastOption","input","handleBlur","isFocussed","parseInputIntoOptions","add","trim","decls","handleEnter","generateVariants","onFormChange","le","getActiveChannel","currencyCode","activeChannel","addOption","groupNameInputs","variantFormValues","enabled","copyFromDefault","stopPropagation","variantsChange","xt","formArray","buildFormGroupMap","getFeaturedAsset","pendingAssetChanges","optionGroupName","formGroupMap","bt","update","productOption","activeLanguage","customFieldsForm","updateVariantName","codeInputTouched","Zt","getTaxRatesSimple","taxRates","taxRate$","taxCategoryIdChange$","defaultTaxZone","zone","category","grossPrice$","priceChange$","Math","round","taxCategoryId","Tt","editOption","removeFacetValue","selectFacetValue","removeFromChannel","assignToChannel","getGlobalSettings","globalSettings","globalTrackInventory","trackInventory","globalOutOfStockThreshold","outOfStockThreshold","isDefaultChannel","ve","trackById","inventoryIsNotTracked","getTaxCategoryName","getStockOnHandMinValue","getSaleableStockLevel","useGlobalOutOfStockThreshold","stockAllocated","areAllSelected","selectedVariantIds","assetChange","variantId","at","toggleSelectAll","selectionChange","toggleSelectVariant","indexOf","optionName","currentOrPendingFacetValues","pendingFacetValueChanges","facetValues","facetValueIds","isVariantSelected","customOptionFields","getFacetValueIds","At","removeProductFacetValue","selectProductFacetValue","setItemsPerPage","setPage","assignVariantToChannel","removeVariantFromChannel","variantAssetChange","filterInput","navigateToTab","customVariantFields","customOptionGroupFields","autoUpdateVariantNames","product$","ni","Ce","oi","filterOperator","bufferSize","refCount","variants$","te","productVariantMap","taxCategories$","productDetailService","activeTab$","buildVariantFormArray","getProductFormGroup","getFacetValues","in","facetValues$","Xo","ii","productChannels$","channelPriceIncludesTax$","pricesIncludeTax","location","replaceState","createUrlTree","tab","currentChannelIds","channelCode","removeProductsFromChannel","variant","removeVariantsFromChannel","variantAssetsChanged","keys","variantAssetChanges","displayFacetValueModal","variantsToCreateAreValid","createVariantsConfig","every","getUpdatedProduct","console","getUpdatedProductVariants","updateSlugAfterSave","variantFacetValueChanges","priceWithTax","taxCategory","emitEvent","yt","runPendingSearchIndexUpdates","deleteProduct","searchTerm","productSearchInput","setSearchTerm","selectedFacetValueIds$","getAll","setFacetValues","searchProducts","search","term","facetValueOperator","groupByProduct","productVariantId","result$","Ba","getPendingSearchIndexUpdates","pendingSearchIndexUpdates","setQueryParam","page","setFacetValueIds","fvids","rebuildSearchIndex","reindex","info","jobQueueService","addJob","state","Intl","NumberFormat","format","duration","indexedItemCount","time","Pt","optionGroupCustomFields","optionCustomFields","optionGroups$","getOptionGroups","getOptions","invalid","getUpdatedOptionGroup","updateProductOptionGroup","getUpdatedOption","updatedAt","setControl","Ft","confirm","removeOptionGroup","onFormChanged","deleteVariant","Ot","initOptionsAndVariants","formValueChanged","getVariantsToAdd","generatedVariants","existing","getVariantName","addOptionGroup","isNew","optionsChanged","removeOptionGroupFromProduct","deleteProductOption","getVariantPrototype","Le","isDefault","optionsAreEqual","optionsAreSubset","gr","reFetchProduct","checkUniqueSkus","confirmDeletionOfObsoleteVariants","addOptionGroupsToProduct","addNewOptionsToGroups","fetchOptionGroups","createNewProductVariants","deleteObsoleteVariants","getObsoleteVariants","hasOnlyDefaultVariant","productOptionGroupId","addOptionToGroup","getProductOptionGroup","productOptionGroup","_r","getProductVariantsOptions","flat","groupId","toOptionString","It","fileSize","mimeType","width","height","source","preview","focalPoint","getAsset","Mt","breadcrumbs","getCollection","kt","Lt","Vt","it","Ve","component","breadcrumb","resolve","we","Je","De","Ue","Ne","qe","breadcrumbKey","getName","link","Se","Kt","$e","Qe","Ee","addFacetValues","mode","query","ids","products","facetValuesRemoved","mutate","wt","Ye","icon","iconClass","requiresPermission","onClick","injector","selection","hostComponent","clearSelection","deleteCollections","Ge","isVisible","assignCollectionsToChannel","collectionIds","Gt","je","getTranslationVars","removeCollectionsFromChannel","Be","deleteFacets","He","assignFacetsToChannel","facetIds","Re","removeFacetsFromChannel","force","then","removedCount","ze","deleteProducts","Ke","We","Xe","registerBulkAction","St","A"],"sources":["./src/lib/catalog/src/components/asset-detail/asset-detail.component.html","./src/lib/catalog/src/components/asset-detail/asset-detail.component.ts","./src/lib/catalog/src/components/asset-list/asset-list.component.ts","./src/lib/catalog/src/components/asset-list/asset-list.component.html","./src/lib/catalog/src/components/assets/assets.component.html","./src/lib/catalog/src/components/assets/assets.component.ts","./src/lib/catalog/src/components/collection-contents/collection-contents.component.html","./src/lib/catalog/src/components/collection-contents/collection-contents.component.ts","./src/lib/catalog/src/components/collection-detail/collection-detail.component.html","./src/lib/catalog/src/components/collection-detail/collection-detail.component.ts","./src/lib/catalog/src/components/collection-tree/array-to-tree.ts","./src/lib/catalog/src/components/collection-tree/collection-tree.service.ts","./src/lib/catalog/src/components/collection-tree/collection-tree-node.component.html","./src/lib/catalog/src/components/collection-tree/collection-tree-node.component.ts","./src/lib/catalog/src/components/collection-tree/collection-tree.component.html","./src/lib/catalog/src/components/collection-tree/collection-tree.component.ts","./src/lib/catalog/src/components/collection-list/collection-list.component.html","./src/lib/catalog/src/components/collection-list/collection-list.component.ts","./src/lib/catalog/src/components/facet-detail/facet-detail.component.html","./src/lib/catalog/src/components/facet-detail/facet-detail.component.ts","./src/lib/catalog/src/components/facet-list/facet-list.component.html","./src/lib/catalog/src/components/facet-list/facet-list.component.ts","./src/lib/catalog/src/components/apply-facet-dialog/apply-facet-dialog.component.html","./src/lib/catalog/src/components/apply-facet-dialog/apply-facet-dialog.component.ts","./src/lib/catalog/src/components/assign-products-to-channel-dialog/assign-products-to-channel-dialog.component.html","./src/lib/catalog/src/components/assign-products-to-channel-dialog/assign-products-to-channel-dialog.component.ts","./src/lib/catalog/src/providers/product-detail/replace-last.ts","./src/lib/catalog/src/providers/product-detail/product-detail.service.ts","./node_modules/@angular-devkit/build-angular/src/babel/webpack-loader.js","./src/lib/catalog/src/components/option-value-input/option-value-input.component.html","./src/lib/catalog/src/components/option-value-input/option-value-input.component.ts","./src/lib/catalog/src/components/generate-product-variants/generate-product-variants.component.html","./src/lib/catalog/src/components/generate-product-variants/generate-product-variants.component.ts","./src/lib/catalog/src/components/product-variants-table/product-variants-table.component.html","./src/lib/catalog/src/components/product-variants-table/product-variants-table.component.ts","./src/lib/catalog/src/components/update-product-option-dialog/update-product-option-dialog.component.html","./src/lib/catalog/src/components/update-product-option-dialog/update-product-option-dialog.component.ts","./src/lib/catalog/src/components/variant-price-detail/variant-price-detail.component.html","./src/lib/catalog/src/components/variant-price-detail/variant-price-detail.component.ts","./src/lib/catalog/src/components/product-variants-list/product-variants-list.component.html","./src/lib/catalog/src/components/product-variants-list/product-variants-list.component.ts","./src/lib/catalog/src/components/product-detail/product-detail.component.html","./src/lib/catalog/src/components/product-detail/product-detail.component.ts","./src/lib/catalog/src/components/product-list/product-list.component.html","./src/lib/catalog/src/components/product-list/product-list.component.ts","./src/lib/catalog/src/components/product-options-editor/product-options-editor.component.html","./src/lib/catalog/src/components/product-options-editor/product-options-editor.component.ts","./src/lib/catalog/src/components/confirm-variant-deletion-dialog/confirm-variant-deletion-dialog.component.html","./src/lib/catalog/src/components/confirm-variant-deletion-dialog/confirm-variant-deletion-dialog.component.ts","./src/lib/catalog/src/components/product-variants-editor/product-variants-editor.component.html","./src/lib/catalog/src/components/product-variants-editor/product-variants-editor.component.ts","./src/lib/catalog/src/providers/routing/asset-resolver.ts","./src/lib/catalog/src/providers/routing/collection-resolver.ts","./src/lib/catalog/src/providers/routing/facet-resolver.ts","./src/lib/catalog/src/providers/routing/product-resolver.ts","./src/lib/catalog/src/providers/routing/product-variants-resolver.ts","./src/lib/catalog/src/catalog.routes.ts","./src/lib/catalog/src/components/assign-to-channel-dialog/assign-to-channel-dialog.component.html","./src/lib/catalog/src/components/assign-to-channel-dialog/assign-to-channel-dialog.component.ts","./src/lib/catalog/src/components/bulk-add-facet-values-dialog/bulk-add-facet-values-dialog.graphql.ts","./src/lib/catalog/src/components/bulk-add-facet-values-dialog/bulk-add-facet-values-dialog.component.html","./src/lib/catalog/src/components/bulk-add-facet-values-dialog/bulk-add-facet-values-dialog.component.ts","./src/lib/catalog/src/components/collection-list/collection-list-bulk-actions.ts","./src/lib/catalog/src/components/facet-list/facet-list-bulk-actions.ts","./src/lib/catalog/src/components/product-list/product-list-bulk-actions.ts","./src/lib/catalog/src/catalog.module.ts"],"sourcesContent":["<vdr-action-bar>\r\n <vdr-ab-left>\r\n <vdr-entity-info [entity]=\"entity$ | async\"></vdr-entity-info>\r\n </vdr-ab-left>\r\n\r\n <vdr-ab-right>\r\n <vdr-action-bar-items locationId=\"asset-detail\"></vdr-action-bar-items>\r\n <button\r\n *vdrIfPermissions=\"['UpdateCatalog', 'UpdateAsset']\"\r\n class=\"btn btn-primary\"\r\n (click)=\"save()\"\r\n [disabled]=\"detailForm.invalid || detailForm.pristine\"\r\n >\r\n {{ 'common.update' | translate }}\r\n </button>\r\n </vdr-ab-right>\r\n</vdr-action-bar>\r\n<vdr-asset-preview\r\n [asset]=\"entity$ | async\"\r\n [editable]=\"true\"\r\n [customFields]=\"customFields\"\r\n [customFieldsForm]=\"detailForm.get('customFields')\"\r\n (assetChange)=\"onAssetChange($event)\"\r\n></vdr-asset-preview>\r\n","import { ChangeDetectionStrategy, Component, OnDestroy, OnInit } from '@angular/core';\r\nimport { FormBuilder, FormControl, FormGroup } from '@angular/forms';\r\nimport { ActivatedRoute, Router } from '@angular/router';\r\nimport { marker as _ } from '@biesbjerg/ngx-translate-extract-marker';\r\nimport {\r\n Asset,\r\n BaseDetailComponent,\r\n CustomFieldConfig,\r\n DataService,\r\n GetAssetQuery,\r\n LanguageCode,\r\n NotificationService,\r\n ServerConfigService,\r\n} from '@vendure/admin-ui/core';\r\n\r\n@Component({\r\n selector: 'vdr-asset-detail',\r\n templateUrl: './asset-detail.component.html',\r\n styleUrls: ['./asset-detail.component.scss'],\r\n changeDetection: ChangeDetectionStrategy.OnPush,\r\n})\r\nexport class AssetDetailComponent\r\n extends BaseDetailComponent<NonNullable<GetAssetQuery['asset']>>\r\n implements OnInit, OnDestroy\r\n{\r\n detailForm = new FormGroup({});\r\n customFields: CustomFieldConfig[];\r\n\r\n constructor(\r\n router: Router,\r\n route: ActivatedRoute,\r\n serverConfigService: ServerConfigService,\r\n private notificationService: NotificationService,\r\n protected dataService: DataService,\r\n private formBuilder: FormBuilder,\r\n ) {\r\n super(route, router, serverConfigService, dataService);\r\n this.customFields = this.getCustomFieldConfig('Asset');\r\n }\r\n\r\n ngOnInit() {\r\n this.detailForm = new FormGroup({\r\n name: new FormControl(''),\r\n tags: new FormControl([]),\r\n customFields: this.formBuilder.group(\r\n this.customFields.reduce((hash, field) => ({ ...hash, [field.name]: '' }), {}),\r\n ),\r\n });\r\n this.init();\r\n }\r\n\r\n ngOnDestroy() {\r\n this.destroy();\r\n }\r\n\r\n onAssetChange(event: { id: string; name: string; tags: string[] }) {\r\n this.detailForm.get('name')?.setValue(event.name);\r\n this.detailForm.get('tags')?.setValue(event.tags);\r\n this.detailForm.markAsDirty();\r\n }\r\n\r\n save() {\r\n this.dataService.product\r\n .updateAsset({\r\n id: this.id,\r\n name: this.detailForm.value.name,\r\n tags: this.detailForm.value.tags,\r\n customFields: this.detailForm.value.customFields,\r\n })\r\n .subscribe(\r\n () => {\r\n this.notificationService.success(_('common.notify-update-success'), { entity: 'Asset' });\r\n },\r\n err => {\r\n this.notificationService.error(_('common.notify-update-error'), {\r\n entity: 'Asset',\r\n });\r\n },\r\n );\r\n }\r\n\r\n protected setFormValues(entity: NonNullable<GetAssetQuery['asset']>, languageCode: LanguageCode): void {\r\n this.detailForm.get('name')?.setValue(entity.name);\r\n this.detailForm.get('tags')?.setValue(entity.tags);\r\n if (this.customFields.length) {\r\n this.setCustomFieldFormValues(this.customFields, this.detailForm.get(['customFields']), entity);\r\n }\r\n }\r\n}\r\n","import { Component, OnInit } from '@angular/core';\r\nimport { ActivatedRoute, Router } from '@angular/router';\r\nimport { marker as _ } from '@biesbjerg/ngx-translate-extract-marker';\r\nimport {\r\n Asset,\r\n BaseListComponent,\r\n DataService,\r\n DeletionResult,\r\n GetAssetListQuery,\r\n GetAssetListQueryVariables,\r\n ItemOf,\r\n LogicalOperator,\r\n ModalService,\r\n NotificationService,\r\n SortOrder,\r\n TagFragment,\r\n} from '@vendure/admin-ui/core';\r\nimport { PaginationInstance } from 'ngx-pagination';\r\nimport { BehaviorSubject, combineLatest, EMPTY, Observable } from 'rxjs';\r\nimport { debounceTime, finalize, map, switchMap, takeUntil } from 'rxjs/operators';\r\n\r\n@Component({\r\n selector: 'vdr-asset-list',\r\n templateUrl: './asset-list.component.html',\r\n styleUrls: ['./asset-list.component.scss'],\r\n})\r\nexport class AssetListComponent\r\n extends BaseListComponent<\r\n GetAssetListQuery,\r\n ItemOf<GetAssetListQuery, 'assets'>,\r\n GetAssetListQueryVariables\r\n >\r\n implements OnInit\r\n{\r\n searchTerm$ = new BehaviorSubject<string | undefined>(undefined);\r\n filterByTags$ = new BehaviorSubject<TagFragment[] | undefined>(undefined);\r\n uploading = false;\r\n allTags$: Observable<TagFragment[]>;\r\n paginationConfig$: Observable<PaginationInstance>;\r\n\r\n constructor(\r\n private notificationService: NotificationService,\r\n private modalService: ModalService,\r\n private dataService: DataService,\r\n router: Router,\r\n route: ActivatedRoute,\r\n ) {\r\n super(router, route);\r\n super.setQueryFn(\r\n (...args: any[]) => this.dataService.product.getAssetList(...args),\r\n data => data.assets,\r\n (skip, take) => {\r\n const searchTerm = this.searchTerm$.value;\r\n const tags = this.filterByTags$.value?.map(t => t.value);\r\n return {\r\n options: {\r\n skip,\r\n take,\r\n ...(searchTerm\r\n ? {\r\n filter: {\r\n name: { contains: searchTerm },\r\n },\r\n }\r\n : {}),\r\n sort: {\r\n createdAt: SortOrder.DESC,\r\n },\r\n tags,\r\n tagsOperator: LogicalOperator.AND,\r\n },\r\n };\r\n },\r\n { take: 25, skip: 0 },\r\n );\r\n }\r\n\r\n ngOnInit() {\r\n super.ngOnInit();\r\n this.paginationConfig$ = combineLatest(this.itemsPerPage$, this.currentPage$, this.totalItems$).pipe(\r\n map(([itemsPerPage, currentPage, totalItems]) => ({ itemsPerPage, currentPage, totalItems })),\r\n );\r\n this.searchTerm$.pipe(debounceTime(250), takeUntil(this.destroy$)).subscribe(() => this.refresh());\r\n\r\n this.filterByTags$.pipe(takeUntil(this.destroy$)).subscribe(() => this.refresh());\r\n this.allTags$ = this.dataService.product.getTagList().mapStream(data => data.tags.items);\r\n }\r\n\r\n filesSelected(files: File[]) {\r\n if (files.length) {\r\n this.uploading = true;\r\n this.dataService.product\r\n .createAssets(files)\r\n .pipe(finalize(() => (this.uploading = false)))\r\n .subscribe(({ createAssets }) => {\r\n let successCount = 0;\r\n for (const result of createAssets) {\r\n switch (result.__typename) {\r\n case 'Asset':\r\n successCount++;\r\n break;\r\n case 'MimeTypeError':\r\n this.notificationService.error(result.message);\r\n break;\r\n }\r\n }\r\n if (0 < successCount) {\r\n super.refresh();\r\n this.notificationService.success(_('asset.notify-create-assets-success'), {\r\n count: successCount,\r\n });\r\n }\r\n });\r\n }\r\n }\r\n\r\n deleteAssets(assets: Asset[]) {\r\n this.showModalAndDelete(assets.map(a => a.id))\r\n .pipe(\r\n switchMap(response => {\r\n if (response.result === DeletionResult.DELETED) {\r\n return [true];\r\n } else {\r\n return this.showModalAndDelete(\r\n assets.map(a => a.id),\r\n response.message || '',\r\n ).pipe(map(r => r.result === DeletionResult.DELETED));\r\n }\r\n }),\r\n )\r\n .subscribe(\r\n () => {\r\n this.notificationService.success(_('common.notify-delete-success'), {\r\n entity: 'Assets',\r\n });\r\n this.refresh();\r\n },\r\n err => {\r\n this.notificationService.error(_('common.notify-delete-error'), {\r\n entity: 'Assets',\r\n });\r\n },\r\n );\r\n }\r\n\r\n private showModalAndDelete(assetIds: string[], message?: string) {\r\n return this.modalService\r\n .dialog({\r\n title: _('catalog.confirm-delete-assets'),\r\n translationVars: {\r\n count: assetIds.length,\r\n },\r\n body: message,\r\n buttons: [\r\n { type: 'secondary', label: _('common.cancel') },\r\n { type: 'danger', label: _('common.delete'), returnValue: true },\r\n ],\r\n })\r\n .pipe(\r\n switchMap(res => (res ? this.dataService.product.deleteAssets(assetIds, !!message) : EMPTY)),\r\n map(res => res.deleteAssets),\r\n );\r\n }\r\n}\r\n","<vdr-action-bar>\r\n <vdr-ab-left [grow]=\"true\">\r\n <vdr-asset-search-input\r\n class=\"pr4 mt1\"\r\n [tags]=\"allTags$ | async\"\r\n (searchTermChange)=\"searchTerm$.next($event)\"\r\n (tagsChange)=\"filterByTags$.next($event)\"\r\n ></vdr-asset-search-input>\r\n </vdr-ab-left>\r\n <vdr-ab-right>\r\n <vdr-action-bar-items locationId=\"asset-list\"></vdr-action-bar-items>\r\n <vdr-asset-file-input\r\n (selectFiles)=\"filesSelected($event)\"\r\n [uploading]=\"uploading\"\r\n dropZoneTarget=\".content-area\"\r\n ></vdr-asset-file-input>\r\n </vdr-ab-right>\r\n</vdr-action-bar>\r\n\r\n<vdr-asset-gallery\r\n [assets]=\"(items$ | async)! | paginate: (paginationConfig$ | async) || {}\"\r\n [multiSelect]=\"true\"\r\n [canDelete]=\"['DeleteCatalog', 'DeleteAsset'] | hasPermission\"\r\n (deleteAssets)=\"deleteAssets($event)\"\r\n></vdr-asset-gallery>\r\n\r\n<div class=\"paging-controls\">\r\n <vdr-items-per-page-controls\r\n [itemsPerPage]=\"itemsPerPage$ | async\"\r\n (itemsPerPageChange)=\"setItemsPerPage($event)\"\r\n ></vdr-items-per-page-controls>\r\n\r\n <vdr-pagination-controls\r\n [currentPage]=\"currentPage$ | async\"\r\n [itemsPerPage]=\"itemsPerPage$ | async\"\r\n [totalItems]=\"totalItems$ | async\"\r\n (pageChange)=\"setPageNumber($event)\"\r\n ></vdr-pagination-controls>\r\n</div>\r\n","<div class=\"card\" *ngIf=\"!compact; else compactView\">\r\n <div class=\"card-img\">\r\n <div class=\"featured-asset\">\r\n <img\r\n *ngIf=\"featuredAsset\"\r\n [src]=\"featuredAsset | assetPreview:'small'\"\r\n (click)=\"previewAsset(featuredAsset)\"\r\n />\r\n <div class=\"placeholder\" *ngIf=\"!featuredAsset\" (click)=\"selectAssets()\">\r\n <clr-icon shape=\"image\" size=\"128\"></clr-icon>\r\n <div>{{ 'catalog.no-featured-asset' | translate }}</div>\r\n </div>\r\n </div>\r\n </div>\r\n <div class=\"card-block\"><ng-container *ngTemplateOutlet=\"assetList\"></ng-container></div>\r\n <div class=\"card-footer\" *vdrIfPermissions=\"updatePermissions\">\r\n <button class=\"btn\" (click)=\"selectAssets()\">\r\n <clr-icon shape=\"attachment\"></clr-icon>\r\n {{ 'asset.add-asset' | translate }}\r\n </button>\r\n </div>\r\n</div>\r\n\r\n<ng-template #compactView>\r\n <div class=\"featured-asset compact\">\r\n <img\r\n *ngIf=\"featuredAsset\"\r\n [src]=\"featuredAsset | assetPreview:'thumb'\"\r\n (click)=\"previewAsset(featuredAsset)\"\r\n />\r\n\r\n <div class=\"placeholder\" *ngIf=\"!featuredAsset\" (click)=\"selectAssets()\"><clr-icon shape=\"image\" size=\"150\"></clr-icon></div>\r\n </div>\r\n <ng-container *ngTemplateOutlet=\"assetList\"></ng-container>\r\n <button\r\n *vdrIfPermissions=\"updatePermissions\"\r\n class=\"compact-select btn btn-icon btn-sm btn-block\"\r\n [title]=\"'asset.add-asset' | translate\"\r\n (click)=\"selectAssets()\"\r\n >\r\n <clr-icon shape=\"attachment\"></clr-icon>\r\n {{ 'asset.add-asset' | translate }}\r\n </button>\r\n</ng-template>\r\n\r\n<ng-template #assetList>\r\n <div class=\"all-assets\" [class.compact]=\"compact\" cdkDropListGroup>\r\n <div\r\n *ngFor=\"let asset of assets; let index = index\"\r\n class=\"drop-list\"\r\n cdkDropList\r\n cdkDropListOrientation=\"horizontal\"\r\n [cdkDropListData]=\"index\"\r\n [cdkDropListDisabled]=\"!(updatePermissions | hasPermission)\"\r\n (cdkDropListDropped)=\"dropListDropped($event)\"\r\n >\r\n <vdr-dropdown cdkDrag>\r\n <div\r\n class=\"asset-thumb\"\r\n vdrDropdownTrigger\r\n [class.featured]=\"isFeatured(asset)\"\r\n [title]=\"\"\r\n tabindex=\"0\"\r\n >\r\n <img [src]=\"asset | assetPreview:'tiny'\" />\r\n </div>\r\n <vdr-dropdown-menu vdrPosition=\"bottom-right\">\r\n <button type=\"button\" vdrDropdownItem (click)=\"previewAsset(asset)\">\r\n {{ 'asset.preview' | translate }}\r\n </button>\r\n <button\r\n type=\"button\"\r\n [disabled]=\"isFeatured(asset) || !(updatePermissions | hasPermission)\"\r\n vdrDropdownItem\r\n (click)=\"setAsFeatured(asset)\"\r\n >\r\n {{ 'asset.set-as-featured-asset' | translate }}\r\n </button>\r\n <div class=\"dropdown-divider\"></div>\r\n <button\r\n type=\"button\"\r\n class=\"remove-asset\"\r\n vdrDropdownItem\r\n [disabled]=\"!(updatePermissions | hasPermission)\"\r\n (click)=\"removeAsset(asset)\"\r\n >\r\n {{ 'asset.remove-asset' | translate }}\r\n </button>\r\n </vdr-dropdown-menu>\r\n </vdr-dropdown>\r\n </div>\r\n </div>\r\n</ng-template>\r\n","import { CdkDragDrop, moveItemInArray } from '@angular/cdk/drag-drop';\r\nimport {\r\n ChangeDetectionStrategy,\r\n ChangeDetectorRef,\r\n Component,\r\n EventEmitter,\r\n HostBinding,\r\n Input,\r\n Output,\r\n} from '@angular/core';\r\nimport {\r\n Asset,\r\n AssetPickerDialogComponent,\r\n AssetPreviewDialogComponent,\r\n ModalService,\r\n Permission,\r\n} from '@vendure/admin-ui/core';\r\nimport { unique } from '@vendure/common/lib/unique';\r\n\r\nexport interface AssetChange {\r\n assets: Asset[];\r\n featuredAsset: Asset | undefined;\r\n}\r\n\r\n/**\r\n * A component which displays the Assets, and allows assets to be removed and\r\n * added, and for the featured asset to be set.\r\n *\r\n * Note: rather complex code for drag drop is due to a limitation of the default CDK implementation\r\n * which is addressed by a work-around from here: https://github.com/angular/components/issues/13372#issuecomment-483998378\r\n */\r\n@Component({\r\n selector: 'vdr-assets',\r\n templateUrl: './assets.component.html',\r\n styleUrls: ['./assets.component.scss'],\r\n changeDetection: ChangeDetectionStrategy.OnPush,\r\n})\r\nexport class AssetsComponent {\r\n @Input('assets') set assetsSetter(val: Asset[]) {\r\n // create a new non-readonly array of assets\r\n this.assets = (val || []).slice();\r\n }\r\n\r\n @Input() featuredAsset: Asset | undefined;\r\n @HostBinding('class.compact')\r\n @Input()\r\n compact = false;\r\n @Output() change = new EventEmitter<AssetChange>();\r\n\r\n public assets: Asset[] = [];\r\n\r\n @Input()\r\n updatePermissions: string | string[] | Permission | Permission[];\r\n\r\n constructor(private modalService: ModalService, private changeDetector: ChangeDetectorRef) {}\r\n\r\n selectAssets() {\r\n this.modalService\r\n .fromComponent(AssetPickerDialogComponent, {\r\n size: 'xl',\r\n })\r\n .subscribe(result => {\r\n if (result && result.length) {\r\n this.assets = unique(this.assets.concat(result), 'id');\r\n if (!this.featuredAsset) {\r\n this.featuredAsset = result[0];\r\n }\r\n this.emitChangeEvent(this.assets, this.featuredAsset);\r\n this.changeDetector.markForCheck();\r\n }\r\n });\r\n }\r\n\r\n setAsFeatured(asset: Asset) {\r\n this.featuredAsset = asset;\r\n this.emitChangeEvent(this.assets, asset);\r\n }\r\n\r\n isFeatured(asset: Asset): boolean {\r\n return !!this.featuredAsset && this.featuredAsset.id === asset.id;\r\n }\r\n\r\n previewAsset(asset: Asset) {\r\n this.modalService\r\n .fromComponent(AssetPreviewDialogComponent, {\r\n size: 'xl',\r\n closable: true,\r\n locals: { asset },\r\n })\r\n .subscribe();\r\n }\r\n\r\n removeAsset(asset: Asset) {\r\n this.assets = this.assets.filter(a => a.id !== asset.id);\r\n if (this.featuredAsset && this.featuredAsset.id === asset.id) {\r\n this.featuredAsset = this.assets.length > 0 ? this.assets[0] : undefined;\r\n }\r\n this.emitChangeEvent(this.assets, this.featuredAsset);\r\n }\r\n\r\n private emitChangeEvent(assets: Asset[], featuredAsset: Asset | undefined) {\r\n this.change.emit({\r\n assets,\r\n featuredAsset,\r\n });\r\n }\r\n\r\n dropListDropped(event: CdkDragDrop<number>) {\r\n moveItemInArray(this.assets, event.previousContainer.data, event.container.data);\r\n this.emitChangeEvent(this.assets, this.featuredAsset);\r\n }\r\n}\r\n","<div class=\"contents-header\">\r\n <div class=\"header-title-row\">\r\n <ng-container\r\n *ngTemplateOutlet=\"headerTemplate; context: { $implicit: contentsTotalItems$ | async }\"\r\n ></ng-container>\r\n </div>\r\n <input\r\n type=\"text\"\r\n [placeholder]=\"'catalog.filter-by-name' | translate\"\r\n [formControl]=\"filterTermControl\"\r\n />\r\n</div>\r\n<div class=\"table-wrapper\">\r\n <div class=\"progress loop\" [class.visible]=\"isLoading\"></div>\r\n <vdr-data-table\r\n [class.loading]=\"isLoading\"\r\n [items]=\"contents$ | async\"\r\n [itemsPerPage]=\"contentsItemsPerPage$ | async\"\r\n [totalItems]=\"contentsTotalItems$ | async\"\r\n [currentPage]=\"contentsCurrentPage$ | async\"\r\n (pageChange)=\"setContentsPageNumber($event)\"\r\n (itemsPerPageChange)=\"setContentsItemsPerPage($event)\"\r\n >\r\n <ng-template let-variant=\"item\">\r\n <td class=\"left align-middle\">{{ variant.name }}</td>\r\n <td class=\"left align-middle\"><small class=\"sku\">{{ variant.sku }}</small></td>\r\n <td class=\"right align-middle\">\r\n <vdr-table-row-action\r\n iconShape=\"edit\"\r\n [label]=\"'common.edit' | translate\"\r\n [linkTo]=\"['/catalog/products', variant.productId, { tab: 'variants' }]\"\r\n ></vdr-table-row-action>\r\n </td>\r\n </ng-template>\r\n </vdr-data-table>\r\n</div>\r\n","import {\r\n ChangeDetectionStrategy,\r\n Component,\r\n ContentChild,\r\n Input,\r\n OnChanges,\r\n OnDestroy,\r\n OnInit,\r\n SimpleChanges,\r\n TemplateRef,\r\n} from '@angular/core';\r\nimport { FormControl } from '@angular/forms';\r\nimport { ActivatedRoute, Router } from '@angular/router';\r\nimport {\r\n CollectionFilterParameter,\r\n ConfigurableOperationInput,\r\n DataService,\r\n GetCollectionContentsQuery,\r\n} from '@vendure/admin-ui/core';\r\nimport { BehaviorSubject, combineLatest, Observable, of, Subject } from 'rxjs';\r\nimport {\r\n catchError,\r\n debounceTime,\r\n distinctUntilChanged,\r\n filter,\r\n finalize,\r\n map,\r\n startWith,\r\n switchMap,\r\n takeUntil,\r\n tap,\r\n} from 'rxjs/operators';\r\n\r\n@Component({\r\n selector: 'vdr-collection-contents',\r\n templateUrl: './collection-contents.component.html',\r\n styleUrls: ['./collection-contents.component.scss'],\r\n changeDetection: ChangeDetectionStrategy.OnPush,\r\n})\r\nexport class CollectionContentsComponent implements OnInit, OnChanges, OnDestroy {\r\n @Input() collectionId: string;\r\n @Input() parentId: string;\r\n @Input() inheritFilters: boolean;\r\n @Input() updatedFilters: ConfigurableOperationInput[] | undefined;\r\n @Input() previewUpdatedFilters = false;\r\n @ContentChild(TemplateRef, { static: true }) headerTemplate: TemplateRef<any>;\r\n\r\n contents$: Observable<NonNullable<GetCollectionContentsQuery['collection']>['productVariants']['items']>;\r\n contentsTotalItems$: Observable<number>;\r\n contentsItemsPerPage$: Observable<number>;\r\n contentsCurrentPage$: Observable<number>;\r\n filterTermControl = new FormControl('');\r\n isLoading = false;\r\n private collectionIdChange$ = new BehaviorSubject<string>('');\r\n private parentIdChange$ = new BehaviorSubject<string>('');\r\n private filterChanges$ = new BehaviorSubject<ConfigurableOperationInput[]>([]);\r\n private inheritFiltersChanges$ = new BehaviorSubject<boolean>(true);\r\n private refresh$ = new BehaviorSubject<boolean>(true);\r\n private destroy$ = new Subject<void>();\r\n\r\n constructor(private route: ActivatedRoute, private router: Router, private dataService: DataService) {}\r\n\r\n ngOnInit() {\r\n this.contentsCurrentPage$ = this.route.queryParamMap.pipe(\r\n map(qpm => qpm.get('contentsPage')),\r\n map(page => (!page ? 1 : +page)),\r\n startWith(1),\r\n distinctUntilChanged(),\r\n );\r\n\r\n this.contentsItemsPerPage$ = this.route.queryParamMap.pipe(\r\n map(qpm => qpm.get('contentsPerPage')),\r\n map(perPage => (!perPage ? 10 : +perPage)),\r\n startWith(10),\r\n distinctUntilChanged(),\r\n );\r\n\r\n const filterTerm$ = this.filterTermControl.valueChanges.pipe(\r\n debounceTime(250),\r\n tap(() => this.setContentsPageNumber(1)),\r\n startWith(''),\r\n );\r\n\r\n const filterChanges$ = this.filterChanges$.asObservable().pipe(\r\n filter(() => this.previewUpdatedFilters),\r\n tap(() => this.setContentsPageNumber(1)),\r\n startWith([]),\r\n );\r\n\r\n const inheritFiltersChanges$ = this.inheritFiltersChanges$.asObservable().pipe(\r\n filter(() => this.inheritFilters != null),\r\n distinctUntilChanged(),\r\n tap(() => this.setContentsPageNumber(1)),\r\n startWith(true),\r\n );\r\n\r\n const fetchUpdate$ = combineLatest(\r\n this.collectionIdChange$,\r\n this.parentIdChange$,\r\n this.contentsCurrentPage$,\r\n this.contentsItemsPerPage$,\r\n filterTerm$,\r\n filterChanges$,\r\n inheritFiltersChanges$,\r\n this.refresh$,\r\n );\r\n\r\n const collection$ = fetchUpdate$.pipe(\r\n takeUntil(this.destroy$),\r\n tap(() => (this.isLoading = true)),\r\n debounceTime(50),\r\n switchMap(([id, parentId, currentPage, itemsPerPage, filterTerm, filters, inheritFilters]) => {\r\n const take = itemsPerPage;\r\n const skip = (currentPage - 1) * itemsPerPage;\r\n if (filters.length && this.previewUpdatedFilters) {\r\n const filterClause = filterTerm\r\n ? ({ name: { contains: filterTerm } } as CollectionFilterParameter)\r\n : undefined;\r\n return this.dataService.collection\r\n .previewCollectionVariants(\r\n {\r\n parentId,\r\n filters,\r\n inheritFilters,\r\n },\r\n {\r\n take,\r\n skip,\r\n filter: filterClause,\r\n },\r\n )\r\n .mapSingle(data => data.previewCollectionVariants)\r\n .pipe(catchError(() => of({ items: [], totalItems: 0 })));\r\n } else if (id) {\r\n return this.dataService.collection\r\n .getCollectionContents(id, take, skip, filterTerm)\r\n .mapSingle(data => data.collection?.productVariants);\r\n } else {\r\n return of(null);\r\n }\r\n }),\r\n tap(() => (this.isLoading = false)),\r\n finalize(() => (this.isLoading = false)),\r\n );\r\n\r\n this.contents$ = collection$.pipe(map(result => (result ? result.items : [])));\r\n this.contentsTotalItems$ = collection$.pipe(map(result => (result ? result.totalItems : 0)));\r\n }\r\n\r\n ngOnChanges(changes: SimpleChanges): void {\r\n if ('collectionId' in changes) {\r\n this.collectionIdChange$.next(changes.collectionId.currentValue);\r\n }\r\n if ('parentId' in changes) {\r\n this.parentIdChange$.next(changes.parentId.currentValue);\r\n }\r\n if ('inheritFilters' in changes) {\r\n this.inheritFiltersChanges$.next(changes.inheritFilters.currentValue);\r\n }\r\n if ('updatedFilters' in changes) {\r\n if (this.updatedFilters) {\r\n this.filterChanges$.next(this.updatedFilters);\r\n }\r\n }\r\n }\r\n\r\n ngOnDestroy() {\r\n this.destroy$.next();\r\n this.destroy$.complete();\r\n }\r\n\r\n setContentsPageNumber(page: number) {\r\n this.setParam('contentsPage', page);\r\n }\r\n\r\n setContentsItemsPerPage(perPage: number) {\r\n this.setParam('contentsPerPage', perPage);\r\n }\r\n\r\n refresh() {\r\n this.refresh$.next(true);\r\n }\r\n\r\n private setParam(key: string, value: any) {\r\n this.router.navigate(['./'], {\r\n relativeTo: this.route,\r\n queryParams: {\r\n [key]: value,\r\n },\r\n queryParamsHandling: 'merge',\r\n replaceUrl: true,\r\n });\r\n }\r\n}\r\n","<vdr-action-bar>\r\n <vdr-ab-left>\r\n <vdr-entity-info [entity]=\"entity$ | async\"></vdr-entity-info>\r\n <vdr-language-selector\r\n [disabled]=\"isNew$ | async\"\r\n [availableLanguageCodes]=\"availableLanguages$ | async\"\r\n [currentLanguageCode]=\"languageCode$ | async\"\r\n (languageCodeChange)=\"setLanguage($event)\"\r\n ></vdr-language-selector>\r\n </vdr-ab-left>\r\n\r\n <vdr-ab-right>\r\n <vdr-action-bar-items locationId=\"collection-detail\"></vdr-action-bar-items>\r\n <button\r\n class=\"btn btn-primary\"\r\n *ngIf=\"isNew$ | async; else updateButton\"\r\n (click)=\"create()\"\r\n [disabled]=\"detailForm.invalid || detailForm.pristine\"\r\n >\r\n {{ 'common.create' | translate }}\r\n </button>\r\n <ng-template #updateButton>\r\n <button\r\n *vdrIfPermissions=\"updatePermission\"\r\n class=\"btn btn-primary\"\r\n (click)=\"save()\"\r\n [disabled]=\"(detailForm.invalid || detailForm.pristine) && !assetsChanged()\"\r\n >\r\n {{ 'common.update' | translate }}\r\n </button>\r\n </ng-template>\r\n </vdr-ab-right>\r\n</vdr-action-bar>\r\n<form class=\"form\" [formGroup]=\"detailForm\" *ngIf=\"entity$ | async as collection\">\r\n\r\n <nav role=\"navigation\">\r\n <ul class=\"collection-breadcrumbs\">\r\n <li *ngFor=\"let breadcrumb of collection.breadcrumbs; let isFirst = first; let isLast = last\">\r\n <a [routerLink]=\"['/catalog/collections']\" *ngIf=\"isFirst\">{{ 'catalog.root-collection' | translate }}</a>\r\n <a [routerLink]=\"['/catalog/collections', breadcrumb.id]\" *ngIf=\"!isFirst && !isLast\">{{ breadcrumb.name | translate }}</a>\r\n <ng-container *ngIf=\"isLast\">{{ breadcrumb.name | translate }}</ng-container>\r\n </li>\r\n </ul>\r\n </nav>\r\n <div class=\"clr-row\">\r\n <div class=\"clr-col\">\r\n <vdr-form-field [label]=\"'catalog.visibility' | translate\" for=\"visibility\">\r\n <clr-toggle-wrapper>\r\n <input\r\n type=\"checkbox\"\r\n clrToggle\r\n formControlName=\"visible\"\r\n id=\"visibility\"\r\n [vdrDisabled]=\"!(updatePermission | hasPermission)\"\r\n />\r\n <label class=\"visible-toggle\">\r\n <ng-container *ngIf=\"detailForm.value.visible; else private\">{{\r\n 'catalog.public' | translate\r\n }}</ng-container>\r\n <ng-template #private>{{ 'catalog.private' | translate }}</ng-template>\r\n </label>\r\n </clr-toggle-wrapper>\r\n </vdr-form-field>\r\n <vdr-form-field [label]=\"'common.name' | translate\" for=\"name\">\r\n <input\r\n id=\"name\"\r\n type=\"text\"\r\n formControlName=\"name\"\r\n [readonly]=\"!(updatePermission | hasPermission)\"\r\n (input)=\"updateSlug($event.target.value)\"\r\n />\r\n </vdr-form-field>\r\n <vdr-form-field\r\n [label]=\"'catalog.slug' | translate\"\r\n for=\"slug\"\r\n [errors]=\"{ pattern: ('catalog.slug-pattern-error' | translate) }\"\r\n >\r\n <input\r\n id=\"slug\"\r\n type=\"text\"\r\n formControlName=\"slug\"\r\n [readonly]=\"!(updatePermission | hasPermission)\"\r\n />\r\n </vdr-form-field>\r\n <vdr-rich-text-editor\r\n formControlName=\"description\"\r\n [readonly]=\"!(updatePermission | hasPermission)\"\r\n [label]=\"'common.description' | translate\"\r\n ></vdr-rich-text-editor>\r\n\r\n <section formGroupName=\"customFields\" *ngIf=\"customFields.length\">\r\n <label>{{ 'common.custom-fields' | translate }}</label>\r\n <vdr-tabbed-custom-fields\r\n entityName=\"Collection\"\r\n [customFields]=\"customFields\"\r\n [customFieldsFormGroup]=\"detailForm.get(['customFields'])\"\r\n [readonly]=\"!(updatePermission | hasPermission)\"\r\n ></vdr-tabbed-custom-fields>\r\n </section>\r\n <vdr-custom-detail-component-host\r\n locationId=\"collection-detail\"\r\n [entity$]=\"entity$\"\r\n [detailForm]=\"detailForm\"\r\n ></vdr-custom-detail-component-host>\r\n </div>\r\n <div class=\"clr-col-md-auto\">\r\n <vdr-assets\r\n [assets]=\"collection.assets\"\r\n [featuredAsset]=\"collection.featuredAsset\"\r\n [updatePermissions]=\"updatePermission\"\r\n (change)=\"assetChanges = $event\"\r\n ></vdr-assets>\r\n </div>\r\n </div>\r\n <div class=\"clr-row\">\r\n <div class=\"clr-col\">\r\n <label>{{ 'catalog.filters' | translate }}</label>\r\n <vdr-form-field [label]=\"'catalog.filter-inheritance' | translate\" for=\"inheritFilters\">\r\n <clr-toggle-wrapper>\r\n <input\r\n type=\"checkbox\"\r\n clrToggle\r\n formControlName=\"inheritFilters\"\r\n id=\"inheritFilters\"\r\n [vdrDisabled]=\"!(updatePermission | hasPermission)\"\r\n />\r\n <label class=\"visible-toggle\">\r\n <ng-container *ngIf=\"detailForm.value.inheritFilters; else noInherit\">{{\r\n 'catalog.inherit-filters-from-parent' | translate\r\n }}</ng-container>\r\n <ng-template #noInherit>{{\r\n 'catalog.do-not-inherit-filters' | translate\r\n }}</ng-template>\r\n </label>\r\n </clr-toggle-wrapper>\r\n </vdr-form-field>\r\n <div formArrayName=\"filters\">\r\n <ng-container *ngFor=\"let filter of filters; index as i; trackBy:trackByFn\">\r\n <vdr-configurable-input\r\n (remove)=\"removeFilter(i)\"\r\n [position]=\"i\"\r\n [operation]=\"filter\"\r\n [operationDefinition]=\"getFilterDefinition(filter)\"\r\n [formControlName]=\"i\"\r\n [readonly]=\"!(updatePermission | hasPermission)\"\r\n ></vdr-configurable-input>\r\n </ng-container>\r\n </div>\r\n\r\n <div *vdrIfPermissions=\"updatePermission\">\r\n <vdr-dropdown>\r\n <button class=\"btn btn-outline\" vdrDropdownTrigger>\r\n <clr-icon shape=\"plus\"></clr-icon>\r\n {{ 'marketing.add-condition' | translate }}\r\n </button>\r\n <vdr-dropdown-menu vdrPosition=\"bottom-left\">\r\n <button\r\n *ngFor=\"let filter of allFilters\"\r\n type=\"button\"\r\n vdrDropdownItem\r\n (click)=\"addFilter(filter)\"\r\n >\r\n {{ filter.description }}\r\n </button>\r\n </vdr-dropdown-menu>\r\n </vdr-dropdown>\r\n </div>\r\n </div>\r\n <div class=\"clr-col\">\r\n <vdr-collection-contents\r\n [collectionId]=\"id\"\r\n [parentId]=\"parentId$ | async\"\r\n [updatedFilters]=\"updatedFilters$ | async\"\r\n [inheritFilters]=\"inheritFilters$ | async\"\r\n [previewUpdatedFilters]=\"livePreview\"\r\n #collectionContents\r\n >\r\n <ng-template let-count>\r\n <div class=\"contents-title\">\r\n {{ 'catalog.collection-contents' | translate }} ({{\r\n 'common.results-count' | translate: {count: count}\r\n }})\r\n </div>\r\n <clr-checkbox-wrapper [class.disabled]=\"detailForm.get('filters')?.pristine\">\r\n <input\r\n type=\"checkbox\"\r\n clrCheckbox\r\n [ngModelOptions]=\"{ standalone: true }\"\r\n [disabled]=\"detailForm.get('filters')?.pristine\"\r\n [ngModel]=\"livePreview\"\r\n (ngModelChange)=\"toggleLivePreview()\"\r\n />\r\n <label>{{ 'catalog.live-preview-contents' | translate }}</label>\r\n </clr-checkbox-wrapper>\r\n </ng-template>\r\n </vdr-collection-contents>\r\n </div>\r\n </div>\r\n</form>\r\n","import {\r\n ChangeDetectionStrategy,\r\n ChangeDetectorRef,\r\n Component,\r\n OnDestroy,\r\n OnInit,\r\n ViewChild,\r\n} from '@angular/core';\r\nimport { FormArray, FormBuilder, FormControl, FormGroup, Validators } from '@angular/forms';\r\nimport { ActivatedRoute, Router } from '@angular/router';\r\nimport { marker as _ } from '@biesbjerg/ngx-translate-extract-marker';\r\nimport {\r\n Asset,\r\n BaseDetailComponent,\r\n Collection,\r\n CollectionFragment,\r\n ConfigurableOperation,\r\n ConfigurableOperationDefinition,\r\n ConfigurableOperationInput,\r\n CreateCollectionInput,\r\n createUpdatedTranslatable,\r\n CustomFieldConfig,\r\n DataService,\r\n encodeConfigArgValue,\r\n findTranslation,\r\n getConfigArgValue,\r\n LanguageCode,\r\n LocalStorageService,\r\n ModalService,\r\n NotificationService,\r\n Permission,\r\n ServerConfigService,\r\n unicodePatternValidator,\r\n UpdateCollectionInput,\r\n} from '@vendure/admin-ui/core';\r\nimport { normalizeString } from '@vendure/common/lib/normalize-string';\r\nimport { combineLatest, merge, Observable, of, Subject } from 'rxjs';\r\nimport { debounceTime, distinctUntilChanged, filter, map, mergeMap, switchMap, take } from 'rxjs/operators';\r\n\r\nimport { CollectionContentsComponent } from '../collection-contents/collection-contents.component';\r\n\r\n@Component({\r\n selector: 'vdr-collection-detail',\r\n templateUrl: './collection-detail.component.html',\r\n styleUrls: ['./collection-detail.component.scss'],\r\n changeDetection: ChangeDetectionStrategy.OnPush,\r\n})\r\nexport class CollectionDetailComponent\r\n extends BaseDetailComponent<CollectionFragment>\r\n implements OnInit, OnDestroy\r\n{\r\n customFields: CustomFieldConfig[];\r\n detailForm: FormGroup;\r\n assetChanges: { assets?: Asset[]; featuredAsset?: Asset } = {};\r\n filters: ConfigurableOperation[] = [];\r\n allFilters: ConfigurableOperationDefinition[] = [];\r\n updatedFilters$: Observable<ConfigurableOperationInput[]>;\r\n inheritFilters$: Observable<boolean>;\r\n livePreview = false;\r\n parentId$: Observable<string | undefined>;\r\n readonly updatePermission = [Permission.UpdateCatalog, Permission.UpdateCollection];\r\n private filterRemoved$ = new Subject<void>();\r\n @ViewChild('collectionContents') contentsComponent: CollectionContentsComponent;\r\n\r\n constructor(\r\n router: Router,\r\n route: ActivatedRoute,\r\n serverConfigService: ServerConfigService,\r\n private changeDetector: ChangeDetectorRef,\r\n protected dataService: DataService,\r\n private formBuilder: FormBuilder,\r\n private notificationService: NotificationService,\r\n private modalService: ModalService,\r\n private localStorageService: LocalStorageService,\r\n ) {\r\n super(route, router, serverConfigService, dataService);\r\n this.customFields = this.getCustomFieldConfig('Collection');\r\n this.detailForm = this.formBuilder.group({\r\n name: ['', Validators.required],\r\n slug: ['', unicodePatternValidator(/^[\\p{Letter}0-9_-]+$/)],\r\n description: '',\r\n visible: false,\r\n inheritFilters: true,\r\n filters: this.formBuilder.array([]),\r\n customFields: this.formBuilder.group(\r\n this.customFields.reduce((hash, field) => ({ ...hash, [field.name]: '' }), {}),\r\n ),\r\n });\r\n this.livePreview = this.localStorageService.get('livePreviewCollectionContents') ?? false;\r\n }\r\n\r\n ngOnInit() {\r\n this.init();\r\n this.dataService.collection.getCollectionFilters().single$.subscribe(res => {\r\n this.allFilters = res.collectionFilters;\r\n });\r\n const filtersFormArray = this.detailForm.get('filters') as FormArray;\r\n const inheritFiltersControl = this.detailForm.get('inheritFilters') as FormControl;\r\n this.inheritFilters$ = inheritFiltersControl.valueChanges.pipe(distinctUntilChanged());\r\n this.updatedFilters$ = merge(filtersFormArray.statusChanges, this.filterRemoved$).pipe(\r\n debounceTime(200),\r\n filter(() => filtersFormArray.touched),\r\n map(() =>\r\n this.mapOperationsToInputs(this.filters, filtersFormArray.value).filter(_filter => {\r\n // ensure all the arguments have valid values. E.g. a newly-added\r\n // filter will not yet have valid values\r\n for (const arg of _filter.arguments) {\r\n if (arg.value === '') {\r\n return false;\r\n }\r\n }\r\n return true;\r\n }),\r\n ),\r\n );\r\n this.parentId$ = this.route.paramMap.pipe(\r\n map(pm => pm.get('parentId') || undefined),\r\n switchMap(parentId => {\r\n if (parentId) {\r\n return of(parentId);\r\n } else {\r\n return this.entity$.pipe(map(collection => collection.parent?.id));\r\n }\r\n }),\r\n );\r\n }\r\n\r\n ngOnDestroy() {\r\n this.destroy();\r\n }\r\n\r\n getFilterDefinition(_filter: ConfigurableOperation): ConfigurableOperationDefinition | undefined {\r\n return this.allFilters.find(f => f.code === _filter.code);\r\n }\r\n\r\n assetsChanged(): boolean {\r\n return !!Object.values(this.assetChanges).length;\r\n }\r\n\r\n /**\r\n * If creating a new Collection, automatically generate the slug based on the collection name.\r\n */\r\n updateSlug(nameValue: string) {\r\n combineLatest(this.entity$, this.languageCode$)\r\n .pipe(take(1))\r\n .subscribe(([entity, languageCode]) => {\r\n const slugControl = this.detailForm.get(['slug']);\r\n const currentTranslation = findTranslation(entity, languageCode);\r\n const currentSlugIsEmpty = !currentTranslation || !currentTranslation.slug;\r\n if (slugControl && slugControl.pristine && currentSlugIsEmpty) {\r\n slugControl.setValue(normalizeString(`${nameValue}`, '-'));\r\n }\r\n });\r\n }\r\n\r\n addFilter(collectionFilter: ConfigurableOperation) {\r\n const filtersArray = this.detailForm.get('filters') as FormArray;\r\n const argsHash = collectionFilter.args.reduce(\r\n (output, arg) => ({\r\n ...output,\r\n [arg.name]: getConfigArgValue(arg.value),\r\n }),\r\n {},\r\n );\r\n filtersArray.push(\r\n this.formBuilder.control({\r\n code: collectionFilter.code,\r\n args: argsHash,\r\n }),\r\n );\r\n this.filters.push({\r\n code: collectionFilter.code,\r\n args: collectionFilter.args.map(a => ({ name: a.name, value: getConfigArgValue(a.value) })),\r\n });\r\n }\r\n\r\n removeFilter(index: number) {\r\n const filtersArray = this.detailForm.get('filters') as FormArray;\r\n if (index !== -1) {\r\n filtersArray.removeAt(index);\r\n filtersArray.markAsDirty();\r\n filtersArray.markAsTouched();\r\n this.filters.splice(index, 1);\r\n this.filterRemoved$.next();\r\n }\r\n }\r\n\r\n create() {\r\n if (!this.detailForm.dirty) {\r\n return;\r\n }\r\n combineLatest(this.entity$, this.languageCode$)\r\n .pipe(\r\n take(1),\r\n mergeMap(([category, languageCode]) => {\r\n const input = this.getUpdatedCollection(\r\n category,\r\n this.detailForm,\r\n languageCode,\r\n ) as CreateCollectionInput;\r\n const parentId = this.route.snapshot.paramMap.get('parentId');\r\n if (parentId) {\r\n input.parentId = parentId;\r\n }\r\n return this.dataService.collection.createCollection(input);\r\n }),\r\n )\r\n .subscribe(\r\n data => {\r\n this.notificationService.success(_('common.notify-create-success'), {\r\n entity: 'Collection',\r\n });\r\n this.assetChanges = {};\r\n this.detailForm.markAsPristine();\r\n this.changeDetector.markForCheck();\r\n this.router.navigate(['../', data.createCollection.id], { relativeTo: this.route });\r\n },\r\n err => {\r\n this.notificationService.error(_('common.notify-create-error'), {\r\n entity: 'Collection',\r\n });\r\n },\r\n );\r\n }\r\n\r\n save() {\r\n combineLatest(this.entity$, this.languageCode$)\r\n .pipe(\r\n take(1),\r\n mergeMap(([category, languageCode]) => {\r\n const input = this.getUpdatedCollection(\r\n category,\r\n this.detailForm,\r\n languageCode,\r\n ) as UpdateCollectionInput;\r\n return this.dataService.collection.updateCollection(input);\r\n }),\r\n )\r\n .subscribe(\r\n () => {\r\n this.assetChanges = {};\r\n this.detailForm.markAsPristine();\r\n this.changeDetector.markForCheck();\r\n this.notificationService.success(_('common.notify-update-success'), {\r\n entity: 'Collection',\r\n });\r\n this.contentsComponent.refresh();\r\n },\r\n err => {\r\n this.notificationService.error(_('common.notify-update-error'), {\r\n entity: 'Collection',\r\n });\r\n },\r\n );\r\n }\r\n\r\n canDeactivate(): boolean {\r\n return super.canDeactivate() && !this.assetChanges.assets && !this.assetChanges.featuredAsset;\r\n }\r\n\r\n toggleLivePreview() {\r\n this.livePreview = !this.livePreview;\r\n this.localStorageService.set('livePreviewCollectionContents', this.livePreview);\r\n }\r\n\r\n trackByFn(index: number, item: ConfigurableOperation) {\r\n return JSON.stringify(item);\r\n }\r\n\r\n /**\r\n * Sets the values of the form on changes to the category or current language.\r\n */\r\n protected setFormValues(entity: CollectionFragment, languageCode: LanguageCode) {\r\n const currentTranslation = findTranslation(entity, languageCode);\r\n\r\n this.detailForm.patchValue({\r\n name: currentTranslation ? currentTranslation.name : '',\r\n slug: currentTranslation ? currentTranslation.slug : '',\r\n description: currentTranslation ? currentTranslation.description : '',\r\n visible: !entity.isPrivate,\r\n inheritFilters: entity.inheritFilters,\r\n });\r\n\r\n const formArray = this.detailForm.get('filters') as FormArray;\r\n if (formArray.length !== entity.filters.length) {\r\n formArray.clear();\r\n this.filters = [];\r\n entity.filters.forEach(f => this.addFilter(f));\r\n }\r\n\r\n if (this.customFields.length) {\r\n this.setCustomFieldFormValues(\r\n this.customFields,\r\n this.detailForm.get(['customFields']),\r\n entity,\r\n currentTranslation,\r\n );\r\n }\r\n }\r\n\r\n /**\r\n * Given a category and the value of the form, this method creates an updated copy of the category which\r\n * can then be persisted to the API.\r\n */\r\n private getUpdatedCollection(\r\n category: CollectionFragment,\r\n form: FormGroup,\r\n languageCode: LanguageCode,\r\n ): CreateCollectionInput | UpdateCollectionInput {\r\n const updatedCategory = createUpdatedTranslatable({\r\n translatable: category,\r\n updatedFields: form.value,\r\n customFieldConfig: this.customFields,\r\n languageCode,\r\n defaultTranslation: {\r\n languageCode,\r\n name: category.name || '',\r\n slug: category.slug || '',\r\n description: category.description || '',\r\n },\r\n });\r\n return {\r\n ...updatedCategory,\r\n assetIds: this.assetChanges.assets?.map(a => a.id),\r\n featuredAssetId: this.assetChanges.featuredAsset?.id,\r\n isPrivate: !form.value.visible,\r\n filters: this.mapOperationsToInputs(this.filters, this.detailForm.value.filters),\r\n };\r\n }\r\n\r\n /**\r\n * Maps an array of conditions or actions to the input format expected by the GraphQL API.\r\n */\r\n private mapOperationsToInputs(\r\n operations: ConfigurableOperation[],\r\n formValueOperations: any,\r\n ): ConfigurableOperationInput[] {\r\n return operations.map((o, i) => {\r\n return {\r\n code: o.code,\r\n arguments: Object.entries(formValueOperations[i].args).map(([name, value], j) => {\r\n return {\r\n name,\r\n value: encodeConfigArgValue(value),\r\n };\r\n }),\r\n };\r\n });\r\n }\r\n}\r\n","export type HasParent = { id: string; parent?: { id: string } | null };\r\nexport type TreeNode<T extends HasParent> = T & { children: Array<TreeNode<T>>; expanded: boolean };\r\nexport type RootNode<T extends HasParent> = { id?: string; children: Array<TreeNode<T>> };\r\n\r\n/**\r\n * Builds a tree from an array of nodes which have a parent.\r\n * Based on https://stackoverflow.com/a/31247960/772859, modified to preserve ordering.\r\n */\r\nexport function arrayToTree<T extends HasParent>(\r\n nodes: T[],\r\n currentState?: RootNode<T>,\r\n expandedIds: string[] = [],\r\n): RootNode<T> {\r\n const topLevelNodes: Array<TreeNode<T>> = [];\r\n const mappedArr: { [id: string]: TreeNode<T> } = {};\r\n const currentStateMap = treeToMap(currentState);\r\n\r\n // First map the nodes of the array to an object -> create a hash table.\r\n for (const node of nodes) {\r\n mappedArr[node.id] = { ...(node as any), children: [] };\r\n }\r\n\r\n for (const id of nodes.map(n => n.id)) {\r\n if (mappedArr.hasOwnProperty(id)) {\r\n const mappedElem = mappedArr[id];\r\n mappedElem.expanded = currentStateMap.get(id)?.expanded ?? expandedIds.includes(id);\r\n const parent = mappedElem.parent;\r\n if (!parent) {\r\n continue;\r\n }\r\n // If the element is not at the root level, add it to its parent array of children.\r\n const parentIsRoot = !mappedArr[parent.id];\r\n if (!parentIsRoot) {\r\n if (mappedArr[parent.id]) {\r\n mappedArr[parent.id].children.push(mappedElem);\r\n } else {\r\n mappedArr[parent.id] = { children: [mappedElem] } as any;\r\n }\r\n } else {\r\n topLevelNodes.push(mappedElem);\r\n }\r\n }\r\n }\r\n // tslint:disable-next-line:no-non-null-assertion\r\n const rootId = topLevelNodes.length ? topLevelNodes[0].parent!.id : undefined;\r\n return { id: rootId, children: topLevelNodes };\r\n}\r\n\r\n/**\r\n * Converts an existing tree (as generated by the arrayToTree function) into a flat\r\n * Map. This is used to persist certain states (e.g. `expanded`) when re-building the\r\n * tree.\r\n */\r\nfunction treeToMap<T extends HasParent>(tree?: RootNode<T>): Map<string, TreeNode<T>> {\r\n const nodeMap = new Map<string, TreeNode<T>>();\r\n function visit(node: TreeNode<T>) {\r\n nodeMap.set(node.id, node);\r\n node.children.forEach(visit);\r\n }\r\n if (tree) {\r\n visit(tree as TreeNode<T>);\r\n }\r\n return nodeMap;\r\n}\r\n","import { CdkDragDrop } from '@angular/cdk/drag-drop';\r\nimport { Injectable, OnDestroy } from '@angular/core';\r\nimport { Observable, Subject } from 'rxjs';\r\n\r\nimport { RootNode, TreeNode } from './array-to-tree';\r\nimport { CollectionPartial, RearrangeEvent } from './collection-tree.types';\r\n\r\n/**\r\n * Facilitates communication between the CollectionTreeComponent and child CollectionTreeNodeComponents\r\n * without introducing a cyclic dependency.\r\n */\r\n@Injectable()\r\nexport class CollectionTreeService implements OnDestroy {\r\n private allMoveListItems: Array<{ path: string; id: string; ancestorIdPath: Set<string> }> = [];\r\n private collectionTree: RootNode<CollectionPartial>;\r\n private _rearrange$ = new Subject<RearrangeEvent>();\r\n private _delete$ = new Subject<string>();\r\n\r\n public rearrange$: Observable<RearrangeEvent>;\r\n public delete$: Observable<string>;\r\n\r\n constructor() {\r\n this.rearrange$ = this._rearrange$.asObservable();\r\n this.delete$ = this._delete$.asObservable();\r\n }\r\n\r\n ngOnDestroy() {\r\n this._rearrange$.complete();\r\n this._delete$.complete();\r\n }\r\n\r\n setCollectionTree(tree: RootNode<CollectionPartial>) {\r\n this.collectionTree = tree;\r\n }\r\n\r\n resetMoveList() {\r\n this.allMoveListItems = [];\r\n }\r\n\r\n getMoveListItems(collection: CollectionPartial) {\r\n if (this.allMoveListItems.length === 0) {\r\n this.allMoveListItems = this.calculateAllMoveListItems();\r\n }\r\n return this.allMoveListItems.filter(\r\n item =>\r\n item.id !== collection.id &&\r\n !item.ancestorIdPath.has(collection.id) &&\r\n item.id !== collection.parent?.id,\r\n );\r\n }\r\n\r\n onDrop(event: CdkDragDrop<CollectionPartial | RootNode<CollectionPartial>>) {\r\n const item = event.item.data as CollectionPartial;\r\n const newParent = event.container.data;\r\n const newParentId = newParent.id;\r\n if (newParentId == null) {\r\n throw new Error(`Could not determine the ID of the root Collection`);\r\n }\r\n this._rearrange$.next({\r\n collectionId: item.id,\r\n parentId: newParentId,\r\n index: event.currentIndex,\r\n });\r\n }\r\n\r\n onMove(event: RearrangeEvent) {\r\n this._rearrange$.next(event);\r\n }\r\n\r\n onDelete(id: string) {\r\n this._delete$.next(id);\r\n }\r\n\r\n private calculateAllMoveListItems() {\r\n const visit = (\r\n node: TreeNode<any>,\r\n parentPath: string[],\r\n ancestorIdPath: Set<string>,\r\n output: Array<{ path: string; id: string; ancestorIdPath: Set<string> }>,\r\n ) => {\r\n const path = parentPath.concat(node.name);\r\n output.push({ path: path.slice(1).join(' / ') || 'root', id: node.id, ancestorIdPath });\r\n node.children.forEach(child =>\r\n visit(child, path, new Set<string>([...ancestorIdPath, node.id]), output),\r\n );\r\n return output;\r\n };\r\n return visit(this.collectionTree, [], new Set<string>(), []);\r\n }\r\n}\r\n","<div\r\n cdkDropList\r\n class=\"tree-node\"\r\n #dropList\r\n [cdkDropListData]=\"collectionTree\"\r\n [cdkDropListDisabled]=\"!(hasUpdatePermission$ | async)\"\r\n (cdkDropListDropped)=\"drop($event)\"\r\n>\r\n <div\r\n class=\"collection\"\r\n [class.private]=\"collection.isPrivate\"\r\n *ngFor=\"let collection of collectionTree.children; index as i; trackBy: trackByFn\"\r\n cdkDrag\r\n [cdkDragData]=\"collection\"\r\n >\r\n <div\r\n class=\"collection-detail\"\r\n [ngClass]=\"'depth-' + depth\"\r\n [class.active]=\"collection.id === activeCollectionId\"\r\n >\r\n <div>\r\n <input\r\n type=\"checkbox\"\r\n clrCheckbox\r\n [checked]=\"selectionManager.isSelected(collection)\"\r\n (click)=\"selectionManager.toggleSelection(collection, $event)\"\r\n />\r\n </div>\r\n <div class=\"name\">\r\n <button\r\n class=\"icon-button folder-button\"\r\n [disabled]=\"expandAll\"\r\n *ngIf=\"collection.children?.length; else folderSpacer\"\r\n (click)=\"toggleExpanded(collection)\"\r\n >\r\n <clr-icon shape=\"folder\" *ngIf=\"!collection.expanded && !expandAll\"></clr-icon>\r\n <clr-icon shape=\"folder-open\" *ngIf=\"collection.expanded || expandAll\"></clr-icon>\r\n </button>\r\n <ng-template #folderSpacer>\r\n <div class=\"folder-button-spacer\"></div>\r\n </ng-template>\r\n {{ collection.name }}\r\n </div>\r\n <div class=\"flex-spacer\"></div>\r\n <vdr-chip *ngIf=\"collection.isPrivate\">{{ 'catalog.private' | translate }}</vdr-chip>\r\n <a\r\n class=\"btn btn-link btn-sm\"\r\n [routerLink]=\"['./', { contents: collection.id }]\"\r\n queryParamsHandling=\"preserve\"\r\n >\r\n <clr-icon shape=\"view-list\"></clr-icon>\r\n {{ 'catalog.view-contents' | translate }}\r\n </a>\r\n <a class=\"btn btn-link btn-sm\" [routerLink]=\"['/catalog/collections/', collection.id]\">\r\n <clr-icon shape=\"edit\"></clr-icon>\r\n {{ 'common.edit' | translate }}\r\n </a>\r\n <div class=\"drag-handle\" cdkDragHandle *vdrIfPermissions=\"['UpdateCatalog', 'UpdateCollection']\">\r\n <clr-icon shape=\"drag-handle\" size=\"24\"></clr-icon>\r\n </div>\r\n <vdr-dropdown>\r\n <button class=\"icon-button\" vdrDropdownTrigger (click)=\"getMoveListItems(collection)\">\r\n <clr-icon shape=\"ellipsis-vertical\"></clr-icon>\r\n </button>\r\n <vdr-dropdown-menu vdrPosition=\"bottom-right\">\r\n <a\r\n class=\"dropdown-item\"\r\n [routerLink]=\"['./', 'create', { parentId: collection.id }]\"\r\n *vdrIfPermissions=\"['CreateCatalog', 'CreateCollection']\"\r\n >\r\n <clr-icon shape=\"plus\"></clr-icon>\r\n {{ 'catalog.create-new-collection' | translate }}\r\n </a>\r\n <div class=\"dropdown-divider\"></div>\r\n <button\r\n type=\"button\"\r\n vdrDropdownItem\r\n [disabled]=\"i === 0 || !(hasUpdatePermission$ | async)\"\r\n (click)=\"moveUp(collection, i)\"\r\n >\r\n <clr-icon shape=\"caret up\"></clr-icon>\r\n {{ 'catalog.move-up' | translate }}\r\n </button>\r\n <button\r\n type=\"button\"\r\n vdrDropdownItem\r\n [disabled]=\"\r\n i === collectionTree.children.length - 1 || !(hasUpdatePermission$ | async)\r\n \"\r\n (click)=\"moveDown(collection, i)\"\r\n >\r\n <clr-icon shape=\"caret down\"></clr-icon>\r\n {{ 'catalog.move-down' | translate }}\r\n </button>\r\n <h4 class=\"dropdown-header\">{{ 'catalog.move-to' | translate }}</h4>\r\n <button\r\n type=\"button\"\r\n vdrDropdownItem\r\n *ngFor=\"let item of moveListItems\"\r\n (click)=\"move(collection, item.id)\"\r\n [disabled]=\"!(hasUpdatePermission$ | async)\"\r\n >\r\n <div class=\"move-to-item\">\r\n <div class=\"move-icon\">\r\n <clr-icon shape=\"child-arrow\"></clr-icon>\r\n </div>\r\n <div class=\"path\">\r\n {{ item.path }}\r\n </div>\r\n </div>\r\n </button>\r\n <div class=\"dropdown-divider\"></div>\r\n <button\r\n class=\"button\"\r\n vdrDropdownItem\r\n (click)=\"delete(collection.id)\"\r\n [disabled]=\"!(hasDeletePermission$ | async)\"\r\n >\r\n <clr-icon shape=\"trash\" class=\"is-danger\"></clr-icon>\r\n {{ 'common.delete' | translate }}\r\n </button>\r\n </vdr-dropdown-menu>\r\n </vdr-dropdown>\r\n </div>\r\n <vdr-collection-tree-node\r\n *ngIf=\"collection.expanded || expandAll\"\r\n [expandAll]=\"expandAll\"\r\n [collectionTree]=\"collection\"\r\n [activeCollectionId]=\"activeCollectionId\"\r\n [selectionManager]=\"selectionManager\"\r\n ></vdr-collection-tree-node>\r\n </div>\r\n</div>\r\n","import { CdkDragDrop, moveItemInArray } from '@angular/cdk/drag-drop';\r\nimport {\r\n ChangeDetectionStrategy,\r\n ChangeDetectorRef,\r\n Component,\r\n Input,\r\n OnChanges,\r\n OnDestroy,\r\n OnInit,\r\n Optional,\r\n SimpleChanges,\r\n SkipSelf,\r\n} from '@angular/core';\r\nimport { ActivatedRoute, Router } from '@angular/router';\r\nimport { DataService, Permission, SelectionManager } from '@vendure/admin-ui/core';\r\nimport { Observable, Subscription } from 'rxjs';\r\nimport { map, shareReplay } from 'rxjs/operators';\r\n\r\nimport { RootNode, TreeNode } from './array-to-tree';\r\nimport { CollectionTreeService } from './collection-tree.service';\r\nimport { CollectionPartial } from './collection-tree.types';\r\n\r\n@Component({\r\n selector: 'vdr-collection-tree-node',\r\n templateUrl: './collection-tree-node.component.html',\r\n styleUrls: ['./collection-tree-node.component.scss'],\r\n changeDetection: ChangeDetectionStrategy.OnPush,\r\n})\r\nexport class CollectionTreeNodeComponent implements OnInit, OnChanges, OnDestroy {\r\n depth = 0;\r\n parentName: string;\r\n @Input() collectionTree: TreeNode<CollectionPartial>;\r\n @Input() activeCollectionId: string;\r\n @Input() expandAll = false;\r\n @Input() selectionManager: SelectionManager<CollectionPartial>;\r\n hasUpdatePermission$: Observable<boolean>;\r\n hasDeletePermission$: Observable<boolean>;\r\n moveListItems: Array<{ path: string; id: string }> = [];\r\n private subscription: Subscription;\r\n\r\n constructor(\r\n @SkipSelf() @Optional() private parent: CollectionTreeNodeComponent,\r\n private dataService: DataService,\r\n private collectionTreeService: CollectionTreeService,\r\n private router: Router,\r\n private route: ActivatedRoute,\r\n private changeDetectorRef: ChangeDetectorRef,\r\n ) {\r\n if (parent) {\r\n this.depth = parent.depth + 1;\r\n }\r\n }\r\n\r\n ngOnInit() {\r\n this.parentName = this.collectionTree.name || '<root>';\r\n const permissions$ = this.dataService.client\r\n .userStatus()\r\n .mapStream(data => data.userStatus.permissions)\r\n .pipe(shareReplay(1));\r\n this.hasUpdatePermission$ = permissions$.pipe(\r\n map(\r\n perms =>\r\n perms.includes(Permission.UpdateCatalog) || perms.includes(Permission.UpdateCollection),\r\n ),\r\n );\r\n this.hasDeletePermission$ = permissions$.pipe(\r\n map(\r\n perms =>\r\n perms.includes(Permission.DeleteCatalog) || perms.includes(Permission.DeleteCollection),\r\n ),\r\n );\r\n this.subscription = this.selectionManager?.selectionChanges$.subscribe(() =>\r\n this.changeDetectorRef.markForCheck(),\r\n );\r\n }\r\n\r\n ngOnChanges(changes: SimpleChanges) {\r\n const expandAllChange = changes['expandAll'];\r\n if (expandAllChange) {\r\n if (expandAllChange.previousValue === true && expandAllChange.currentValue === false) {\r\n this.collectionTree.children.forEach(c => (c.expanded = false));\r\n }\r\n }\r\n }\r\n\r\n ngOnDestroy() {\r\n this.subscription?.unsubscribe();\r\n }\r\n\r\n trackByFn(index: number, item: CollectionPartial) {\r\n return item.id;\r\n }\r\n\r\n toggleExpanded(collection: TreeNode<CollectionPartial>) {\r\n collection.expanded = !collection.expanded;\r\n let expandedIds = this.route.snapshot.queryParamMap.get('expanded')?.split(',') ?? [];\r\n if (collection.expanded) {\r\n expandedIds.push(collection.id);\r\n } else {\r\n expandedIds = expandedIds.filter(id => id !== collection.id);\r\n }\r\n this.router.navigate(['./'], {\r\n queryParams: {\r\n expanded: expandedIds.filter(id => !!id).join(','),\r\n },\r\n queryParamsHandling: 'merge',\r\n relativeTo: this.route,\r\n });\r\n }\r\n\r\n getMoveListItems(collection: CollectionPartial) {\r\n this.moveListItems = this.collectionTreeService.getMoveListItems(collection);\r\n }\r\n\r\n move(collection: CollectionPartial, parentId: string) {\r\n this.collectionTreeService.onMove({\r\n index: 0,\r\n parentId,\r\n collectionId: collection.id,\r\n });\r\n }\r\n\r\n moveUp(collection: CollectionPartial, currentIndex: number) {\r\n if (!collection.parent) {\r\n return;\r\n }\r\n this.collectionTreeService.onMove({\r\n index: currentIndex - 1,\r\n parentId: collection.parent.id,\r\n collectionId: collection.id,\r\n });\r\n }\r\n\r\n moveDown(collection: CollectionPartial, currentIndex: number) {\r\n if (!collection.parent) {\r\n return;\r\n }\r\n this.collectionTreeService.onMove({\r\n index: currentIndex + 1,\r\n parentId: collection.parent.id,\r\n collectionId: collection.id,\r\n });\r\n }\r\n\r\n drop(event: CdkDragDrop<CollectionPartial | RootNode<CollectionPartial>>) {\r\n moveItemInArray(this.collectionTree.children, event.previousIndex, event.currentIndex);\r\n this.collectionTreeService.onDrop(event);\r\n }\r\n\r\n delete(id: string) {\r\n this.collectionTreeService.onDelete(id);\r\n }\r\n}\r\n","<vdr-collection-tree-node\r\n *ngIf=\"collectionTree\"\r\n cdkDropListGroup\r\n [expandAll]=\"expandAll\"\r\n [collectionTree]=\"collectionTree\"\r\n [selectionManager]=\"selectionManager\"\r\n [activeCollectionId]=\"activeCollectionId\"\r\n></vdr-collection-tree-node>\r\n","import {\r\n ChangeDetectionStrategy,\r\n Component,\r\n EventEmitter,\r\n Input,\r\n OnChanges,\r\n OnInit,\r\n Output,\r\n SimpleChanges,\r\n} from '@angular/core';\r\nimport { Collection, SelectionManager } from '@vendure/admin-ui/core';\r\n\r\nimport { arrayToTree, RootNode } from './array-to-tree';\r\nimport { CollectionTreeService } from './collection-tree.service';\r\nimport { CollectionPartial, RearrangeEvent } from './collection-tree.types';\r\n\r\n@Component({\r\n selector: 'vdr-collection-tree',\r\n templateUrl: 'collection-tree.component.html',\r\n styleUrls: ['./collection-tree.component.scss'],\r\n changeDetection: ChangeDetectionStrategy.OnPush,\r\n providers: [CollectionTreeService],\r\n})\r\nexport class CollectionTreeComponent implements OnInit, OnChanges {\r\n @Input() collections: CollectionPartial[];\r\n @Input() activeCollectionId: string;\r\n @Input() expandAll = false;\r\n @Input() expandedIds: string[] = [];\r\n @Input() selectionManager: SelectionManager<CollectionPartial>;\r\n @Output() rearrange = new EventEmitter<RearrangeEvent>();\r\n @Output() deleteCollection = new EventEmitter<string>();\r\n collectionTree: RootNode<CollectionPartial>;\r\n\r\n constructor(private collectionTreeService: CollectionTreeService) {}\r\n\r\n ngOnChanges(changes: SimpleChanges) {\r\n if ('collections' in changes && this.collections) {\r\n this.collectionTree = arrayToTree(this.collections, this.collectionTree, this.expandedIds);\r\n this.collectionTreeService.setCollectionTree(this.collectionTree);\r\n this.collectionTreeService.resetMoveList();\r\n }\r\n }\r\n\r\n ngOnInit() {\r\n this.collectionTreeService.rearrange$.subscribe(event => this.rearrange.emit(event));\r\n this.collectionTreeService.delete$.subscribe(id => this.deleteCollection.emit(id));\r\n }\r\n}\r\n","<vdr-action-bar>\r\n <vdr-ab-left>\r\n <div class=\"\">\r\n <input\r\n type=\"text\"\r\n name=\"searchTerm\"\r\n [formControl]=\"filterTermControl\"\r\n [placeholder]=\"'catalog.filter-by-name' | translate\"\r\n class=\"clr-input search-input\"\r\n />\r\n <div class=\"flex center\">\r\n <clr-toggle-wrapper\r\n class=\"expand-all-toggle mt2\"\r\n >\r\n <input type=\"checkbox\" clrToggle [(ngModel)]=\"expandAll\" (change)=\"toggleExpandAll()\" />\r\n <label>\r\n {{ 'catalog.expand-all-collections' | translate }}\r\n </label>\r\n </clr-toggle-wrapper>\r\n <vdr-language-selector\r\n class=\"mt2\"\r\n [availableLanguageCodes]=\"availableLanguages$ | async\"\r\n [currentLanguageCode]=\"contentLanguage$ | async\"\r\n (languageCodeChange)=\"setLanguage($event)\"\r\n ></vdr-language-selector>\r\n </div>\r\n </div>\r\n </vdr-ab-left>\r\n <vdr-ab-right>\r\n <vdr-action-bar-items locationId=\"collection-list\"></vdr-action-bar-items>\r\n <a\r\n class=\"btn btn-primary\"\r\n *vdrIfPermissions=\"['CreateCatalog', 'CreateCollection']\"\r\n [routerLink]=\"['./create']\"\r\n >\r\n <clr-icon shape=\"plus\"></clr-icon>\r\n {{ 'catalog.create-new-collection' | translate }}\r\n </a>\r\n </vdr-ab-right>\r\n</vdr-action-bar>\r\n<div class=\"bulk-select-controls\">\r\n <input\r\n type=\"checkbox\"\r\n clrCheckbox\r\n [checked]=\"selectionManager.areAllCurrentItemsSelected()\"\r\n (click)=\"selectionManager.toggleSelectAll()\"\r\n />\r\n <vdr-bulk-action-menu\r\n class=\"ml2\"\r\n locationId=\"collection-list\"\r\n [hostComponent]=\"this\"\r\n [selectionManager]=\"selectionManager\"\r\n ></vdr-bulk-action-menu>\r\n</div>\r\n<div class=\"collection-wrapper\">\r\n <vdr-collection-tree\r\n [collections]=\"items$ | async\"\r\n [activeCollectionId]=\"activeCollectionId$ | async\"\r\n [expandAll]=\"expandAll\"\r\n [expandedIds]=\"expandedIds\"\r\n [selectionManager]=\"selectionManager\"\r\n (rearrange)=\"onRearrange($event)\"\r\n (deleteCollection)=\"deleteCollection($event)\"\r\n ></vdr-collection-tree>\r\n\r\n <div class=\"collection-contents\" [class.expanded]=\"activeCollectionId$ | async\">\r\n <vdr-collection-contents [collectionId]=\"activeCollectionId$ | async\">\r\n <ng-template let-count>\r\n <div class=\"collection-title\">\r\n {{ activeCollectionTitle$ | async }} ({{\r\n 'common.results-count' | translate: { count: count }\r\n }})\r\n </div>\r\n <button type=\"button\" class=\"close-button\" (click)=\"closeContents()\">\r\n <clr-icon shape=\"close\"></clr-icon>\r\n </button>\r\n </ng-template>\r\n </vdr-collection-contents>\r\n </div>\r\n</div>\r\n","import { ChangeDetectionStrategy, ChangeDetectorRef, Component, OnDestroy, OnInit } from '@angular/core';\r\nimport { FormControl } from '@angular/forms';\r\nimport { ActivatedRoute, Router } from '@angular/router';\r\nimport { marker as _ } from '@biesbjerg/ngx-translate-extract-marker';\r\nimport {\r\n DataService,\r\n GetCollectionListQuery,\r\n ItemOf,\r\n LanguageCode,\r\n ModalService,\r\n NotificationService,\r\n QueryResult,\r\n SelectionManager,\r\n ServerConfigService,\r\n} from '@vendure/admin-ui/core';\r\nimport { combineLatest, EMPTY, Observable, Subject } from 'rxjs';\r\nimport {\r\n debounceTime,\r\n distinctUntilChanged,\r\n map,\r\n shareReplay,\r\n switchMap,\r\n take,\r\n takeUntil,\r\n tap,\r\n} from 'rxjs/operators';\r\n\r\nimport { CollectionPartial, RearrangeEvent } from '../collection-tree/collection-tree.types';\r\n\r\n@Component({\r\n selector: 'vdr-collection-list',\r\n templateUrl: './collection-list.component.html',\r\n styleUrls: ['./collection-list.component.scss'],\r\n changeDetection: ChangeDetectionStrategy.OnPush,\r\n})\r\nexport class CollectionListComponent implements OnInit, OnDestroy {\r\n filterTermControl = new FormControl('');\r\n activeCollectionId$: Observable<string | null>;\r\n activeCollectionTitle$: Observable<string>;\r\n items$: Observable<Array<ItemOf<GetCollectionListQuery, 'collections'>>>;\r\n availableLanguages$: Observable<LanguageCode[]>;\r\n contentLanguage$: Observable<LanguageCode>;\r\n expandAll = false;\r\n expandedIds: string[] = [];\r\n selectionManager: SelectionManager<CollectionPartial>;\r\n private queryResult: QueryResult<any>;\r\n private destroy$ = new Subject<void>();\r\n\r\n constructor(\r\n private dataService: DataService,\r\n private notificationService: NotificationService,\r\n private modalService: ModalService,\r\n private router: Router,\r\n private route: ActivatedRoute,\r\n private serverConfigService: ServerConfigService,\r\n private changeDetectorRef: ChangeDetectorRef,\r\n ) {\r\n this.selectionManager = new SelectionManager({\r\n additiveMode: true,\r\n multiSelect: true,\r\n itemsAreEqual: (a, b) => a.id === b.id,\r\n });\r\n }\r\n\r\n ngOnInit() {\r\n this.queryResult = this.dataService.collection.getCollections(1000, 0).refetchOnChannelChange();\r\n this.items$ = this.queryResult\r\n .mapStream(data => data.collections.items)\r\n .pipe(\r\n tap(items => this.selectionManager.setCurrentItems(items)),\r\n shareReplay(1),\r\n );\r\n this.activeCollectionId$ = this.route.paramMap.pipe(\r\n map(pm => pm.get('contents')),\r\n distinctUntilChanged(),\r\n );\r\n this.expandedIds = this.route.snapshot.queryParamMap.get('expanded')?.split(',') ?? [];\r\n this.expandAll = this.route.snapshot.queryParamMap.get('expanded') === 'all';\r\n\r\n this.activeCollectionTitle$ = combineLatest(this.activeCollectionId$, this.items$).pipe(\r\n map(([id, collections]) => {\r\n if (id) {\r\n const match = collections.find(c => c.id === id);\r\n return match ? match.name : '';\r\n }\r\n return '';\r\n }),\r\n );\r\n this.availableLanguages$ = this.serverConfigService.getAvailableLanguages();\r\n this.contentLanguage$ = this.dataService.client\r\n .uiState()\r\n .mapStream(({ uiState }) => uiState.contentLanguage)\r\n .pipe(tap(() => this.refresh()));\r\n\r\n this.filterTermControl.valueChanges\r\n .pipe(debounceTime(250), takeUntil(this.destroy$))\r\n .subscribe(term => {\r\n this.router.navigate(['./'], {\r\n queryParams: {\r\n q: term || undefined,\r\n },\r\n queryParamsHandling: 'merge',\r\n relativeTo: this.route,\r\n });\r\n });\r\n\r\n this.route.queryParamMap\r\n .pipe(\r\n map(qpm => qpm.get('q')),\r\n distinctUntilChanged(),\r\n takeUntil(this.destroy$),\r\n )\r\n .subscribe(() => this.refresh());\r\n this.filterTermControl.patchValue(this.route.snapshot.queryParamMap.get('q'));\r\n }\r\n\r\n ngOnDestroy() {\r\n this.queryResult.completed$.next();\r\n this.destroy$.next(undefined);\r\n this.destroy$.complete();\r\n }\r\n\r\n toggleExpandAll() {\r\n this.router.navigate(['./'], {\r\n queryParams: {\r\n expanded: this.expandAll ? 'all' : undefined,\r\n },\r\n queryParamsHandling: 'merge',\r\n relativeTo: this.route,\r\n });\r\n }\r\n\r\n onRearrange(event: RearrangeEvent) {\r\n this.dataService.collection.moveCollection([event]).subscribe({\r\n next: () => {\r\n this.notificationService.success(_('common.notify-saved-changes'));\r\n this.refresh();\r\n },\r\n error: err => {\r\n this.notificationService.error(_('common.notify-save-changes-error'));\r\n },\r\n });\r\n }\r\n\r\n deleteCollection(id: string) {\r\n this.items$\r\n .pipe(\r\n take(1),\r\n map(items => -1 < items.findIndex(i => i.parent && i.parent.id === id)),\r\n switchMap(hasChildren => {\r\n return this.modalService.dialog({\r\n title: _('catalog.confirm-delete-collection'),\r\n body: hasChildren\r\n ? _('catalog.confirm-delete-collection-and-children-body')\r\n : undefined,\r\n buttons: [\r\n { type: 'secondary', label: _('common.cancel') },\r\n { type: 'danger', label: _('common.delete'), returnValue: true },\r\n ],\r\n });\r\n }),\r\n switchMap(response => (response ? this.dataService.collection.deleteCollection(id) : EMPTY)),\r\n )\r\n .subscribe(\r\n () => {\r\n this.notificationService.success(_('common.notify-delete-success'), {\r\n entity: 'Collection',\r\n });\r\n this.refresh();\r\n },\r\n err => {\r\n this.notificationService.error(_('common.notify-delete-error'), {\r\n entity: 'Collection',\r\n });\r\n },\r\n );\r\n }\r\n\r\n closeContents() {\r\n const params = { ...this.route.snapshot.params };\r\n delete params.contents;\r\n this.router.navigate(['./', params], { relativeTo: this.route, queryParamsHandling: 'preserve' });\r\n }\r\n\r\n setLanguage(code: LanguageCode) {\r\n this.dataService.client.setContentLanguage(code).subscribe();\r\n }\r\n\r\n refresh() {\r\n const filterTerm = this.route.snapshot.queryParamMap.get('q');\r\n this.queryResult.ref.refetch({\r\n options: {\r\n skip: 0,\r\n take: 1000,\r\n ...(filterTerm\r\n ? {\r\n filter: {\r\n name: {\r\n contains: filterTerm,\r\n },\r\n },\r\n }\r\n : {}),\r\n },\r\n });\r\n }\r\n}\r\n","<vdr-action-bar>\r\n <vdr-ab-left>\r\n <vdr-entity-info [entity]=\"entity$ | async\"></vdr-entity-info>\r\n <vdr-language-selector\r\n [disabled]=\"isNew$ | async\"\r\n [availableLanguageCodes]=\"availableLanguages$ | async\"\r\n [currentLanguageCode]=\"languageCode$ | async\"\r\n (languageCodeChange)=\"setLanguage($event)\"\r\n ></vdr-language-selector>\r\n </vdr-ab-left>\r\n\r\n <vdr-ab-right>\r\n <vdr-action-bar-items locationId=\"facet-detail\"></vdr-action-bar-items>\r\n <button\r\n class=\"btn btn-primary\"\r\n *ngIf=\"isNew$ | async; else updateButton\"\r\n (click)=\"create()\"\r\n [disabled]=\"detailForm.invalid || detailForm.pristine\"\r\n >\r\n {{ 'common.create' | translate }}\r\n </button>\r\n <ng-template #updateButton>\r\n <button\r\n *vdrIfPermissions=\"updatePermission\"\r\n class=\"btn btn-primary\"\r\n (click)=\"save()\"\r\n [disabled]=\"detailForm.invalid || detailForm.pristine\"\r\n >\r\n {{ 'common.update' | translate }}\r\n </button>\r\n </ng-template>\r\n </vdr-ab-right>\r\n</vdr-action-bar>\r\n\r\n<form class=\"form\" [formGroup]=\"detailForm\" *ngIf=\"entity$ | async as facet\">\r\n <section class=\"form-block\" formGroupName=\"facet\">\r\n <vdr-form-field [label]=\"'catalog.visibility' | translate\" for=\"visibility\">\r\n <clr-toggle-wrapper>\r\n <input\r\n type=\"checkbox\"\r\n clrToggle\r\n [vdrDisabled]=\"!(updatePermission | hasPermission)\"\r\n formControlName=\"visible\"\r\n id=\"visibility\"\r\n />\r\n <label class=\"visible-toggle\">\r\n <ng-container *ngIf=\"detailForm.value.facet.visible; else private\">{{\r\n 'catalog.public' | translate\r\n }}</ng-container>\r\n <ng-template #private>{{ 'catalog.private' | translate }}</ng-template>\r\n </label>\r\n </clr-toggle-wrapper>\r\n </vdr-form-field>\r\n <vdr-form-field [label]=\"'common.name' | translate\" for=\"name\">\r\n <input\r\n id=\"name\"\r\n type=\"text\"\r\n formControlName=\"name\"\r\n [readonly]=\"!(updatePermission | hasPermission)\"\r\n (input)=\"updateCode(facet.code, $event.target.value)\"\r\n />\r\n </vdr-form-field>\r\n <vdr-form-field\r\n [label]=\"'common.code' | translate\"\r\n for=\"code\"\r\n [readOnlyToggle]=\"updatePermission | hasPermission\"\r\n >\r\n <input\r\n id=\"code\"\r\n type=\"text\"\r\n [readonly]=\"!(updatePermission | hasPermission)\"\r\n formControlName=\"code\"\r\n />\r\n </vdr-form-field>\r\n\r\n <section formGroupName=\"customFields\" *ngIf=\"customFields.length\">\r\n <label>{{ 'common.custom-fields' | translate }}</label>\r\n <vdr-tabbed-custom-fields\r\n entityName=\"Facet\"\r\n [customFields]=\"customFields\"\r\n [customFieldsFormGroup]=\"detailForm.get(['facet', 'customFields'])\"\r\n [readonly]=\"!(updatePermission | hasPermission)\"\r\n ></vdr-tabbed-custom-fields>\r\n </section>\r\n <vdr-custom-detail-component-host\r\n locationId=\"facet-detail\"\r\n [entity$]=\"entity$\"\r\n [detailForm]=\"detailForm\"\r\n ></vdr-custom-detail-component-host>\r\n </section>\r\n\r\n <section class=\"form-block\" *ngIf=\"!(isNew$ | async)\">\r\n <label>{{ 'catalog.facet-values' | translate }}</label>\r\n\r\n <table class=\"facet-values-list table\" formArrayName=\"values\" *ngIf=\"0 < getValuesFormArray().length\">\r\n <thead>\r\n <tr>\r\n <th></th>\r\n <th>{{ 'common.name' | translate }}</th>\r\n <th>{{ 'common.code' | translate }}</th>\r\n <ng-container *ngIf=\"customValueFields.length\">\r\n <th>{{ 'common.custom-fields' | translate }}</th>\r\n </ng-container>\r\n <th></th>\r\n </tr>\r\n </thead>\r\n <tbody>\r\n <tr class=\"facet-value\" *ngFor=\"let value of values; let i = index\" [formGroupName]=\"i\">\r\n <td class=\"align-middle\">\r\n <vdr-entity-info [entity]=\"value\"></vdr-entity-info>\r\n </td>\r\n <td class=\"align-middle\">\r\n <input\r\n type=\"text\"\r\n formControlName=\"name\"\r\n [readonly]=\"!(updatePermission | hasPermission)\"\r\n (input)=\"updateValueCode(facet.values[i]?.code, $event.target.value, i)\"\r\n />\r\n </td>\r\n <td class=\"align-middle\"><input type=\"text\" formControlName=\"code\" readonly /></td>\r\n <td class=\"\" *ngIf=\"customValueFields.length\">\r\n <vdr-tabbed-custom-fields\r\n entityName=\"FacetValue\"\r\n [customFields]=\"customValueFields\"\r\n [compact]=\"true\"\r\n [customFieldsFormGroup]=\"detailForm.get(['values', i, 'customFields'])\"\r\n [readonly]=\"!(updatePermission | hasPermission)\"\r\n ></vdr-tabbed-custom-fields>\r\n </td>\r\n <td class=\"align-middle\">\r\n <vdr-dropdown>\r\n <button type=\"button\" class=\"btn btn-link btn-sm\" vdrDropdownTrigger>\r\n {{ 'common.actions' | translate }}\r\n <clr-icon shape=\"caret down\"></clr-icon>\r\n </button>\r\n <vdr-dropdown-menu vdrPosition=\"bottom-right\">\r\n <button\r\n type=\"button\"\r\n class=\"delete-button\"\r\n (click)=\"deleteFacetValue(facet.values[i]?.id, i)\"\r\n [disabled]=\"!(updatePermission | hasPermission)\"\r\n vdrDropdownItem\r\n >\r\n <clr-icon shape=\"trash\" class=\"is-danger\"></clr-icon>\r\n {{ 'common.delete' | translate }}\r\n </button>\r\n </vdr-dropdown-menu>\r\n </vdr-dropdown>\r\n </td>\r\n </tr>\r\n </tbody>\r\n </table>\r\n\r\n <div>\r\n <button\r\n type=\"button\"\r\n class=\"btn btn-secondary\"\r\n *vdrIfPermissions=\"['CreateCatalog', 'CreateFacet']\"\r\n (click)=\"addFacetValue()\"\r\n >\r\n <clr-icon shape=\"add\"></clr-icon>\r\n {{ 'catalog.add-facet-value' | translate }}\r\n </button>\r\n </div>\r\n </section>\r\n</form>\r\n","import { ChangeDetectionStrategy, ChangeDetectorRef, Component, OnDestroy, OnInit } from '@angular/core';\r\nimport { FormArray, FormBuilder, FormControl, FormGroup, Validators } from '@angular/forms';\r\nimport { ActivatedRoute, Router } from '@angular/router';\r\nimport { marker as _ } from '@biesbjerg/ngx-translate-extract-marker';\r\nimport {\r\n BaseDetailComponent,\r\n CreateFacetInput,\r\n CreateFacetValueInput,\r\n createUpdatedTranslatable,\r\n CustomFieldConfig,\r\n DataService,\r\n DeletionResult,\r\n FacetWithValuesFragment,\r\n findTranslation,\r\n LanguageCode,\r\n ModalService,\r\n NotificationService,\r\n Permission,\r\n ServerConfigService,\r\n UpdateFacetInput,\r\n UpdateFacetValueInput,\r\n} from '@vendure/admin-ui/core';\r\nimport { normalizeString } from '@vendure/common/lib/normalize-string';\r\nimport { notNullOrUndefined } from '@vendure/common/lib/shared-utils';\r\nimport { combineLatest, EMPTY, forkJoin, Observable } from 'rxjs';\r\nimport { map, mapTo, mergeMap, switchMap, take } from 'rxjs/operators';\r\n\r\n@Component({\r\n selector: 'vdr-facet-detail',\r\n templateUrl: './facet-detail.component.html',\r\n styleUrls: ['./facet-detail.component.scss'],\r\n changeDetection: ChangeDetectionStrategy.OnPush,\r\n})\r\nexport class FacetDetailComponent\r\n extends BaseDetailComponent<FacetWithValuesFragment>\r\n implements OnInit, OnDestroy\r\n{\r\n customFields: CustomFieldConfig[];\r\n customValueFields: CustomFieldConfig[];\r\n detailForm: FormGroup;\r\n values: Array<FacetWithValuesFragment['values'][number] | { name: string; code: string }>;\r\n readonly updatePermission = [Permission.UpdateCatalog, Permission.UpdateFacet];\r\n\r\n constructor(\r\n router: Router,\r\n route: ActivatedRoute,\r\n serverConfigService: ServerConfigService,\r\n private changeDetector: ChangeDetectorRef,\r\n protected dataService: DataService,\r\n private formBuilder: FormBuilder,\r\n private notificationService: NotificationService,\r\n private modalService: ModalService,\r\n ) {\r\n super(route, router, serverConfigService, dataService);\r\n this.customFields = this.getCustomFieldConfig('Facet');\r\n this.customValueFields = this.getCustomFieldConfig('FacetValue');\r\n this.detailForm = this.formBuilder.group({\r\n facet: this.formBuilder.group({\r\n code: ['', Validators.required],\r\n name: '',\r\n visible: true,\r\n customFields: this.formBuilder.group(\r\n this.customFields.reduce((hash, field) => ({ ...hash, [field.name]: '' }), {}),\r\n ),\r\n }),\r\n values: this.formBuilder.array([]),\r\n });\r\n }\r\n\r\n ngOnInit() {\r\n this.init();\r\n }\r\n\r\n ngOnDestroy() {\r\n this.destroy();\r\n }\r\n\r\n updateCode(currentCode: string, nameValue: string) {\r\n if (!currentCode) {\r\n const codeControl = this.detailForm.get(['facet', 'code']);\r\n if (codeControl && codeControl.pristine) {\r\n codeControl.setValue(normalizeString(nameValue, '-'));\r\n }\r\n }\r\n }\r\n\r\n updateValueCode(currentCode: string, nameValue: string, index: number) {\r\n if (!currentCode) {\r\n const codeControl = this.detailForm.get(['values', index, 'code']);\r\n if (codeControl && codeControl.pristine) {\r\n codeControl.setValue(normalizeString(nameValue, '-'));\r\n }\r\n }\r\n }\r\n\r\n customValueFieldIsSet(index: number, name: string): boolean {\r\n return !!this.detailForm.get(['values', index, 'customFields', name]);\r\n }\r\n\r\n getValuesFormArray(): FormArray {\r\n return this.detailForm.get('values') as FormArray;\r\n }\r\n\r\n addFacetValue() {\r\n const valuesFormArray = this.detailForm.get('values') as FormArray | null;\r\n if (valuesFormArray) {\r\n const valueGroup = this.formBuilder.group({\r\n id: '',\r\n name: ['', Validators.required],\r\n code: '',\r\n });\r\n const newValue: any = { name: '', code: '' };\r\n if (this.customValueFields.length) {\r\n const customValueFieldsGroup = new FormGroup({});\r\n newValue.customFields = {};\r\n\r\n for (const fieldDef of this.customValueFields) {\r\n const key = fieldDef.name;\r\n customValueFieldsGroup.addControl(key, new FormControl());\r\n }\r\n\r\n valueGroup.addControl('customFields', customValueFieldsGroup);\r\n }\r\n valuesFormArray.insert(valuesFormArray.length, valueGroup);\r\n this.values.push(newValue);\r\n }\r\n }\r\n\r\n create() {\r\n const facetForm = this.detailForm.get('facet');\r\n if (!facetForm || !facetForm.dirty) {\r\n return;\r\n }\r\n combineLatest(this.entity$, this.languageCode$)\r\n .pipe(\r\n take(1),\r\n mergeMap(([facet, languageCode]) => {\r\n const newFacet = this.getUpdatedFacet(\r\n facet,\r\n facetForm as FormGroup,\r\n languageCode,\r\n ) as CreateFacetInput;\r\n return this.dataService.facet.createFacet(newFacet);\r\n }),\r\n switchMap(data => this.dataService.facet.getAllFacets().single$.pipe(mapTo(data))),\r\n )\r\n .subscribe(\r\n data => {\r\n this.notificationService.success(_('common.notify-create-success'), { entity: 'Facet' });\r\n this.detailForm.markAsPristine();\r\n this.changeDetector.markForCheck();\r\n this.router.navigate(['../', data.createFacet.id], { relativeTo: this.route });\r\n },\r\n err => {\r\n this.notificationService.error(_('common.notify-create-error'), {\r\n entity: 'Facet',\r\n });\r\n },\r\n );\r\n }\r\n\r\n save() {\r\n combineLatest(this.entity$, this.languageCode$)\r\n .pipe(\r\n take(1),\r\n mergeMap(([facet, languageCode]) => {\r\n const facetGroup = this.detailForm.get('facet');\r\n const updateOperations: Array<Observable<any>> = [];\r\n\r\n if (facetGroup && facetGroup.dirty) {\r\n const newFacet = this.getUpdatedFacet(\r\n facet,\r\n facetGroup as FormGroup,\r\n languageCode,\r\n ) as UpdateFacetInput;\r\n if (newFacet) {\r\n updateOperations.push(this.dataService.facet.updateFacet(newFacet));\r\n }\r\n }\r\n const valuesArray = this.detailForm.get('values');\r\n if (valuesArray && valuesArray.dirty) {\r\n const createdValues = this.getCreatedFacetValues(\r\n facet,\r\n valuesArray as FormArray,\r\n languageCode,\r\n );\r\n if (createdValues.length) {\r\n updateOperations.push(\r\n this.dataService.facet\r\n .createFacetValues(createdValues)\r\n .pipe(switchMap(() => this.dataService.facet.getFacet(this.id).single$)),\r\n );\r\n }\r\n const updatedValues = this.getUpdatedFacetValues(\r\n facet,\r\n valuesArray as FormArray,\r\n languageCode,\r\n );\r\n if (updatedValues.length) {\r\n updateOperations.push(this.dataService.facet.updateFacetValues(updatedValues));\r\n }\r\n }\r\n\r\n return forkJoin(updateOperations);\r\n }),\r\n switchMap(() => this.dataService.facet.getAllFacets().single$),\r\n )\r\n .subscribe(\r\n () => {\r\n this.detailForm.markAsPristine();\r\n this.changeDetector.markForCheck();\r\n this.notificationService.success(_('common.notify-update-success'), { entity: 'Facet' });\r\n },\r\n err => {\r\n this.notificationService.error(_('common.notify-update-error'), {\r\n entity: 'Facet',\r\n });\r\n },\r\n );\r\n }\r\n\r\n deleteFacetValue(facetValueId: string | undefined, index: number) {\r\n if (!facetValueId) {\r\n // deleting a newly-added (not persisted) FacetValue\r\n const valuesFormArray = this.detailForm.get('values') as FormArray | null;\r\n if (valuesFormArray) {\r\n valuesFormArray.removeAt(index);\r\n }\r\n this.values.splice(index, 1);\r\n return;\r\n }\r\n this.showModalAndDelete(facetValueId)\r\n .pipe(\r\n switchMap(response => {\r\n if (response.result === DeletionResult.DELETED) {\r\n return [true];\r\n } else {\r\n return this.showModalAndDelete(facetValueId, response.message || '').pipe(\r\n map(r => r.result === DeletionResult.DELETED),\r\n );\r\n }\r\n }),\r\n switchMap(deleted => (deleted ? this.dataService.facet.getFacet(this.id).single$ : [])),\r\n )\r\n .subscribe(\r\n () => {\r\n const valuesFormArray = this.detailForm.get('values') as FormArray | null;\r\n if (valuesFormArray) {\r\n valuesFormArray.removeAt(index);\r\n }\r\n this.notificationService.success(_('common.notify-delete-success'), {\r\n entity: 'FacetValue',\r\n });\r\n },\r\n err => {\r\n this.notificationService.error(_('common.notify-delete-error'), {\r\n entity: 'FacetValue',\r\n });\r\n },\r\n );\r\n }\r\n\r\n private showModalAndDelete(facetValueId: string, message?: string) {\r\n return this.modalService\r\n .dialog({\r\n title: _('catalog.confirm-delete-facet-value'),\r\n body: message,\r\n buttons: [\r\n { type: 'secondary', label: _('common.cancel') },\r\n { type: 'danger', label: _('common.delete'), returnValue: true },\r\n ],\r\n })\r\n .pipe(\r\n switchMap(result =>\r\n result ? this.dataService.facet.deleteFacetValues([facetValueId], !!message) : EMPTY,\r\n ),\r\n map(result => result.deleteFacetValues[0]),\r\n );\r\n }\r\n\r\n /**\r\n * Sets the values of the form on changes to the facet or current language.\r\n */\r\n protected setFormValues(facet: FacetWithValuesFragment, languageCode: LanguageCode) {\r\n const currentTranslation = findTranslation(facet, languageCode);\r\n\r\n this.detailForm.patchValue({\r\n facet: {\r\n code: facet.code,\r\n visible: !facet.isPrivate,\r\n name: currentTranslation?.name ?? '',\r\n },\r\n });\r\n\r\n if (this.customFields.length) {\r\n const customFieldsGroup = this.detailForm.get(['facet', 'customFields']) as FormGroup;\r\n this.setCustomFieldFormValues(\r\n this.customFields,\r\n this.detailForm.get(['facet', 'customFields']),\r\n facet,\r\n currentTranslation,\r\n );\r\n }\r\n\r\n const currentValuesFormArray = this.detailForm.get('values') as FormArray;\r\n this.values = [...facet.values];\r\n facet.values.forEach(value => {\r\n const valueTranslation = findTranslation(value, languageCode);\r\n const group = {\r\n id: value.id,\r\n code: value.code,\r\n name: valueTranslation ? valueTranslation.name : '',\r\n };\r\n let valueControl = currentValuesFormArray.controls.find(\r\n control => control.value.id === value.id,\r\n ) as FormGroup | undefined;\r\n if (valueControl) {\r\n valueControl.get('id')?.setValue(group.id);\r\n valueControl.get('code')?.setValue(group.code);\r\n valueControl.get('name')?.setValue(group.name);\r\n } else {\r\n valueControl = this.formBuilder.group(group);\r\n currentValuesFormArray.push(valueControl);\r\n }\r\n if (this.customValueFields.length) {\r\n let customValueFieldsGroup = valueControl.get(['customFields']) as FormGroup | undefined;\r\n if (!customValueFieldsGroup) {\r\n customValueFieldsGroup = new FormGroup({});\r\n valueControl.addControl('customFields', customValueFieldsGroup);\r\n }\r\n\r\n if (customValueFieldsGroup) {\r\n for (const fieldDef of this.customValueFields) {\r\n const key = fieldDef.name;\r\n const fieldValue =\r\n fieldDef.type === 'localeString'\r\n ? (valueTranslation as any | undefined)?.customFields?.[key]\r\n : (value as any).customFields[key];\r\n const control = customValueFieldsGroup.get(key);\r\n if (control) {\r\n control.setValue(fieldValue);\r\n } else {\r\n customValueFieldsGroup.addControl(key, new FormControl(fieldValue));\r\n }\r\n }\r\n }\r\n }\r\n });\r\n }\r\n\r\n /**\r\n * Given a facet and the value of the detailForm, this method creates an updated copy of the facet which\r\n * can then be persisted to the API.\r\n */\r\n private getUpdatedFacet(\r\n facet: FacetWithValuesFragment,\r\n facetFormGroup: FormGroup,\r\n languageCode: LanguageCode,\r\n ): CreateFacetInput | UpdateFacetInput {\r\n const input = createUpdatedTranslatable({\r\n translatable: facet,\r\n updatedFields: facetFormGroup.value,\r\n customFieldConfig: this.customFields,\r\n languageCode,\r\n defaultTranslation: {\r\n languageCode,\r\n name: facet.name || '',\r\n },\r\n });\r\n input.isPrivate = !facetFormGroup.value.visible;\r\n return input;\r\n }\r\n\r\n /**\r\n * Given an array of facet values and the values from the detailForm, this method creates a new array\r\n * which can be persisted to the API via a createFacetValues mutation.\r\n */\r\n private getCreatedFacetValues(\r\n facet: FacetWithValuesFragment,\r\n valuesFormArray: FormArray,\r\n languageCode: LanguageCode,\r\n ): CreateFacetValueInput[] {\r\n return valuesFormArray.controls\r\n .filter(c => !c.value.id)\r\n .map(c => c.value)\r\n .map(value =>\r\n createUpdatedTranslatable({\r\n translatable: { ...value, translations: [] as any },\r\n updatedFields: value,\r\n customFieldConfig: this.customValueFields,\r\n languageCode,\r\n defaultTranslation: {\r\n languageCode,\r\n name: '',\r\n },\r\n }),\r\n )\r\n .map(input => ({\r\n facetId: facet.id,\r\n ...input,\r\n }));\r\n }\r\n\r\n /**\r\n * Given an array of facet values and the values from the detailForm, this method creates a new array\r\n * which can be persisted to the API via an updateFacetValues mutation.\r\n */\r\n private getUpdatedFacetValues(\r\n facet: FacetWithValuesFragment,\r\n valuesFormArray: FormArray,\r\n languageCode: LanguageCode,\r\n ): UpdateFacetValueInput[] {\r\n const dirtyValues = facet.values.filter((v, i) => {\r\n const formRow = valuesFormArray.get(i.toString());\r\n return formRow && formRow.dirty && formRow.value.id;\r\n });\r\n const dirtyValueValues = valuesFormArray.controls\r\n .filter(c => c.dirty && c.value.id)\r\n .map(c => c.value);\r\n\r\n if (dirtyValues.length !== dirtyValueValues.length) {\r\n throw new Error(_(`error.facet-value-form-values-do-not-match`));\r\n }\r\n return dirtyValues\r\n .map((value, i) => {\r\n return createUpdatedTranslatable({\r\n translatable: value,\r\n updatedFields: dirtyValueValues[i],\r\n customFieldConfig: this.customValueFields,\r\n languageCode,\r\n defaultTranslation: {\r\n languageCode,\r\n name: '',\r\n },\r\n });\r\n })\r\n .filter(notNullOrUndefined);\r\n }\r\n}\r\n","<vdr-action-bar>\r\n <vdr-ab-left>\r\n <div class=\"\">\r\n <input\r\n type=\"text\"\r\n name=\"searchTerm\"\r\n [formControl]=\"filterTermControl\"\r\n [placeholder]=\"'catalog.filter-by-name' | translate\"\r\n class=\"clr-input search-input\"\r\n />\r\n <div>\r\n <vdr-language-selector\r\n [availableLanguageCodes]=\"availableLanguages$ | async\"\r\n [currentLanguageCode]=\"contentLanguage$ | async\"\r\n (languageCodeChange)=\"setLanguage($event)\"\r\n ></vdr-language-selector>\r\n </div>\r\n </div>\r\n </vdr-ab-left>\r\n <vdr-ab-right>\r\n <vdr-action-bar-items locationId=\"facet-list\"></vdr-action-bar-items>\r\n <a\r\n class=\"btn btn-primary\"\r\n *vdrIfPermissions=\"['CreateCatalog', 'CreateFacet']\"\r\n [routerLink]=\"['./create']\"\r\n >\r\n <clr-icon shape=\"plus\"></clr-icon>\r\n {{ 'catalog.create-new-facet' | translate }}\r\n </a>\r\n </vdr-ab-right>\r\n</vdr-action-bar>\r\n\r\n<vdr-data-table\r\n [items]=\"items$ | async\"\r\n [itemsPerPage]=\"itemsPerPage$ | async\"\r\n [totalItems]=\"totalItems$ | async\"\r\n [currentPage]=\"currentPage$ | async\"\r\n (pageChange)=\"setPageNumber($event)\"\r\n (itemsPerPageChange)=\"setItemsPerPage($event)\"\r\n [selectionManager]=\"selectionManager\"\r\n>\r\n <vdr-bulk-action-menu\r\n locationId=\"facet-list\"\r\n [hostComponent]=\"this\"\r\n [selectionManager]=\"selectionManager\"\r\n ></vdr-bulk-action-menu>\r\n <vdr-dt-column>{{ 'common.code' | translate }}</vdr-dt-column>\r\n <vdr-dt-column>{{ 'common.name' | translate }}</vdr-dt-column>\r\n <vdr-dt-column [expand]=\"true\">{{ 'catalog.values' | translate }}</vdr-dt-column>\r\n <vdr-dt-column>{{ 'catalog.visibility' | translate }}</vdr-dt-column>\r\n <vdr-dt-column></vdr-dt-column>\r\n <vdr-dt-column></vdr-dt-column>\r\n <ng-template let-facet=\"item\">\r\n <td class=\"left align-middle\" [class.private]=\"facet.isPrivate\">{{ facet.code }}</td>\r\n <td class=\"left align-middle\" [class.private]=\"facet.isPrivate\">{{ facet.name }}</td>\r\n <td class=\"left align-middle\" [class.private]=\"facet.isPrivate\">\r\n <vdr-facet-value-chip\r\n *ngFor=\"let value of facet.values | slice: 0:displayLimit[facet.id] || 3\"\r\n [facetValue]=\"value\"\r\n [removable]=\"false\"\r\n [displayFacetName]=\"false\"\r\n ></vdr-facet-value-chip>\r\n <button\r\n class=\"btn btn-sm btn-secondary btn-icon\"\r\n *ngIf=\"facet.values.length > initialLimit\"\r\n (click)=\"toggleDisplayLimit(facet)\"\r\n >\r\n <ng-container *ngIf=\"(displayLimit[facet.id] || 0) < facet.values.length; else collapse\">\r\n <clr-icon shape=\"plus\"></clr-icon>\r\n {{ facet.values.length - initialLimit }}\r\n </ng-container>\r\n <ng-template #collapse>\r\n <clr-icon shape=\"minus\"></clr-icon>\r\n </ng-template>\r\n </button>\r\n </td>\r\n <td class=\"left align-middle\" [class.private]=\"facet.isPrivate\">\r\n <vdr-chip>\r\n <ng-container *ngIf=\"!facet.isPrivate; else private\">{{\r\n 'catalog.public' | translate\r\n }}</ng-container>\r\n <ng-template #private>{{ 'catalog.private' | translate }}</ng-template>\r\n </vdr-chip>\r\n </td>\r\n <td class=\"right align-middle\" [class.private]=\"facet.isPrivate\">\r\n <vdr-table-row-action\r\n iconShape=\"edit\"\r\n [label]=\"'common.edit' | translate\"\r\n [linkTo]=\"['./', facet.id]\"\r\n ></vdr-table-row-action>\r\n </td>\r\n <td class=\"right align-middle\" [class.private]=\"facet.isPrivate\">\r\n <vdr-dropdown>\r\n <button type=\"button\" class=\"btn btn-link btn-sm\" vdrDropdownTrigger>\r\n {{ 'common.actions' | translate }}\r\n <clr-icon shape=\"caret down\"></clr-icon>\r\n </button>\r\n <vdr-dropdown-menu vdrPosition=\"bottom-right\">\r\n <button\r\n type=\"button\"\r\n class=\"delete-button\"\r\n (click)=\"deleteFacet(facet.id)\"\r\n [disabled]=\"!(['DeleteCatalog', 'DeleteFacet'] | hasPermission)\"\r\n vdrDropdownItem\r\n >\r\n <clr-icon shape=\"trash\" class=\"is-danger\"></clr-icon>\r\n {{ 'common.delete' | translate }}\r\n </button>\r\n </vdr-dropdown-menu>\r\n </vdr-dropdown>\r\n </td>\r\n </ng-template>\r\n</vdr-data-table>\r\n","import { Component, OnInit } from '@angular/core';\r\nimport { FormControl } from '@angular/forms';\r\nimport { ActivatedRoute, Router } from '@angular/router';\r\nimport { marker as _ } from '@biesbjerg/ngx-translate-extract-marker';\r\nimport {\r\n BaseListComponent,\r\n DataService,\r\n DeletionResult,\r\n GetFacetListQuery,\r\n ItemOf,\r\n LanguageCode,\r\n ModalService,\r\n NotificationService,\r\n SelectionManager,\r\n ServerConfigService,\r\n} from '@vendure/admin-ui/core';\r\nimport { SortOrder } from '@vendure/common/lib/generated-shop-types';\r\nimport { EMPTY, Observable } from 'rxjs';\r\nimport { debounceTime, filter, map, switchMap, takeUntil, tap } from 'rxjs/operators';\r\n\r\n@Component({\r\n selector: 'vdr-facet-list',\r\n templateUrl: './facet-list.component.html',\r\n styleUrls: ['./facet-list.component.scss'],\r\n})\r\nexport class FacetListComponent\r\n extends BaseListComponent<GetFacetListQuery, ItemOf<GetFacetListQuery, 'facets'>>\r\n implements OnInit\r\n{\r\n filterTermControl = new FormControl('');\r\n availableLanguages$: Observable<LanguageCode[]>;\r\n contentLanguage$: Observable<LanguageCode>;\r\n readonly initialLimit = 3;\r\n displayLimit: { [id: string]: number } = {};\r\n selectionManager: SelectionManager<ItemOf<GetFacetListQuery, 'facets'>>;\r\n\r\n constructor(\r\n private dataService: DataService,\r\n private modalService: ModalService,\r\n private notificationService: NotificationService,\r\n private serverConfigService: ServerConfigService,\r\n router: Router,\r\n route: ActivatedRoute,\r\n ) {\r\n super(router, route);\r\n super.setQueryFn(\r\n (...args: any[]) => this.dataService.facet.getFacets(...args).refetchOnChannelChange(),\r\n data => data.facets,\r\n (skip, take) => ({\r\n options: {\r\n skip,\r\n take,\r\n filter: {\r\n name: {\r\n contains: this.filterTermControl.value,\r\n },\r\n },\r\n sort: {\r\n createdAt: SortOrder.DESC,\r\n },\r\n },\r\n }),\r\n );\r\n this.selectionManager = new SelectionManager({\r\n multiSelect: true,\r\n itemsAreEqual: (a, b) => a.id === b.id,\r\n additiveMode: true,\r\n });\r\n }\r\n\r\n ngOnInit() {\r\n super.ngOnInit();\r\n this.availableLanguages$ = this.serverConfigService.getAvailableLanguages();\r\n this.contentLanguage$ = this.dataService.client\r\n .uiState()\r\n .mapStream(({ uiState }) => uiState.contentLanguage)\r\n .pipe(tap(() => this.refresh()));\r\n this.filterTermControl.valueChanges\r\n .pipe(\r\n filter(value => 2 <= value.length || value.length === 0),\r\n debounceTime(250),\r\n takeUntil(this.destroy$),\r\n )\r\n .subscribe(() => this.refresh());\r\n }\r\n\r\n toggleDisplayLimit(facet: ItemOf<GetFacetListQuery, 'facets'>) {\r\n if (this.displayLimit[facet.id] === facet.values.length) {\r\n this.displayLimit[facet.id] = this.initialLimit;\r\n } else {\r\n this.displayLimit[facet.id] = facet.values.length;\r\n }\r\n }\r\n\r\n deleteFacet(facetValueId: string) {\r\n this.showModalAndDelete(facetValueId)\r\n .pipe(\r\n switchMap(response => {\r\n if (response.result === DeletionResult.DELETED) {\r\n return [true];\r\n } else {\r\n return this.showModalAndDelete(facetValueId, response.message || '').pipe(\r\n map(r => r.result === DeletionResult.DELETED),\r\n );\r\n }\r\n }),\r\n // Refresh the cached facets to reflect the changes\r\n switchMap(() => this.dataService.facet.getAllFacets().single$),\r\n )\r\n .subscribe(\r\n () => {\r\n this.notificationService.success(_('common.notify-delete-success'), {\r\n entity: 'FacetValue',\r\n });\r\n this.refresh();\r\n },\r\n err => {\r\n this.notificationService.error(_('common.notify-delete-error'), {\r\n entity: 'FacetValue',\r\n });\r\n },\r\n );\r\n }\r\n\r\n setLanguage(code: LanguageCode) {\r\n this.dataService.client.setContentLanguage(code).subscribe();\r\n }\r\n\r\n private showModalAndDelete(facetId: string, message?: string) {\r\n return this.modalService\r\n .dialog({\r\n title: _('catalog.confirm-delete-facet'),\r\n body: message,\r\n buttons: [\r\n { type: 'secondary', label: _('common.cancel') },\r\n {\r\n type: 'danger',\r\n label: message ? _('common.force-delete') : _('common.delete'),\r\n returnValue: true,\r\n },\r\n ],\r\n })\r\n .pipe(\r\n switchMap(res => (res ? this.dataService.facet.deleteFacet(facetId, !!message) : EMPTY)),\r\n map(res => res.deleteFacet),\r\n );\r\n }\r\n}\r\n","<ng-template vdrDialogTitle>{{ 'catalog.add-facets' | translate }}</ng-template>\r\n\r\n<vdr-facet-value-selector\r\n (selectedValuesChange)=\"selectedValues = $event\"\r\n></vdr-facet-value-selector>\r\n\r\n<ng-template vdrDialogButtons>\r\n <button type=\"button\" class=\"btn\" (click)=\"cancel()\">{{ 'common.cancel' | translate }}</button>\r\n <button\r\n type=\"submit\"\r\n (click)=\"selectValues()\"\r\n [disabled]=\"selectedValues.length === 0\"\r\n class=\"btn btn-primary\"\r\n >\r\n {{ 'catalog.add-facets' | translate }}\r\n </button>\r\n</ng-template>\r\n","import {\r\n AfterViewInit,\r\n ChangeDetectionStrategy,\r\n ChangeDetectorRef,\r\n Component,\r\n ViewChild,\r\n} from '@angular/core';\r\nimport {\r\n Dialog,\r\n FacetValue,\r\n FacetValueSelectorComponent,\r\n FacetWithValuesFragment,\r\n} from '@vendure/admin-ui/core';\r\n\r\n@Component({\r\n selector: 'vdr-apply-facet-dialog',\r\n templateUrl: './apply-facet-dialog.component.html',\r\n styleUrls: ['./apply-facet-dialog.component.scss'],\r\n changeDetection: ChangeDetectionStrategy.OnPush,\r\n})\r\nexport class ApplyFacetDialogComponent implements Dialog<FacetValue[]>, AfterViewInit {\r\n @ViewChild(FacetValueSelectorComponent) private selector: FacetValueSelectorComponent;\r\n resolveWith: (result?: FacetValue[]) => void;\r\n selectedValues: FacetValue[] = [];\r\n // Provided by caller\r\n facets: FacetWithValuesFragment[];\r\n\r\n constructor(private changeDetector: ChangeDetectorRef) {}\r\n\r\n ngAfterViewInit() {\r\n setTimeout(() => this.selector.focus(), 0);\r\n }\r\n\r\n selectValues() {\r\n this.resolveWith(this.selectedValues);\r\n }\r\n\r\n cancel() {\r\n this.resolveWith();\r\n }\r\n}\r\n","<ng-template vdrDialogTitle>\r\n <ng-container *ngIf=\"isProductVariantMode; else productModeTitle\">{{\r\n 'catalog.assign-variants-to-channel' | translate\r\n }}</ng-container>\r\n <ng-template #productModeTitle>{{ 'catalog.assign-products-to-channel' | translate }}</ng-template>\r\n</ng-template>\r\n\r\n<div class=\"flex\">\r\n <clr-input-container>\r\n <label>{{ 'common.channel' | translate }}</label>\r\n <vdr-channel-assignment-control\r\n clrInput\r\n [multiple]=\"false\"\r\n [includeDefaultChannel]=\"false\"\r\n [disableChannelIds]=\"currentChannelIds\"\r\n [formControl]=\"selectedChannelIdControl\"\r\n ></vdr-channel-assignment-control>\r\n </clr-input-container>\r\n <div class=\"flex-spacer\"></div>\r\n <clr-input-container>\r\n <label>{{ 'catalog.price-conversion-factor' | translate }}</label>\r\n <input clrInput type=\"number\" min=\"0\" max=\"99999\" [formControl]=\"priceFactorControl\" />\r\n </clr-input-container>\r\n</div>\r\n\r\n<div class=\"channel-price-preview\">\r\n <label class=\"clr-control-label\">{{ 'catalog.channel-price-preview' | translate }}</label>\r\n <table class=\"table\">\r\n <thead>\r\n <tr>\r\n <th>{{ 'common.name' | translate }}</th>\r\n <th>\r\n {{\r\n 'catalog.price-in-channel'\r\n | translate: { channel: currentChannel?.code | channelCodeToLabel | translate }\r\n }}\r\n </th>\r\n <th>\r\n <ng-template [ngIf]=\"selectedChannel\" [ngIfElse]=\"noSelection\">\r\n {{ 'catalog.price-in-channel' | translate: { channel: selectedChannel?.code } }}\r\n </ng-template>\r\n <ng-template #noSelection>\r\n {{ 'catalog.no-channel-selected' | translate }}\r\n </ng-template>\r\n </th>\r\n </tr>\r\n </thead>\r\n <tbody>\r\n <tr *ngFor=\"let row of variantsPreview$ | async\">\r\n <td>{{ row.name }}</td>\r\n <td>{{ row.price | localeCurrency: currentChannel?.currencyCode }}</td>\r\n <td>\r\n <ng-template [ngIf]=\"selectedChannel\" [ngIfElse]=\"noChannelSelected\">\r\n {{ row.pricePreview | localeCurrency: selectedChannel?.currencyCode }}\r\n </ng-template>\r\n <ng-template #noChannelSelected> - </ng-template>\r\n </td>\r\n </tr>\r\n </tbody>\r\n </table>\r\n</div>\r\n\r\n<ng-template vdrDialogButtons>\r\n <button type=\"button\" class=\"btn\" (click)=\"cancel()\">{{ 'common.cancel' | translate }}</button>\r\n <button type=\"submit\" (click)=\"assign()\" [disabled]=\"!selectedChannel\" class=\"btn btn-primary\">\r\n <ng-template [ngIf]=\"selectedChannel\" [ngIfElse]=\"noSelection\">\r\n {{ 'catalog.assign-to-named-channel' | translate: { channelCode: selectedChannel?.code } }}\r\n </ng-template>\r\n <ng-template #noSelection>\r\n {{ 'catalog.no-channel-selected' | translate }}\r\n </ng-template>\r\n </button>\r\n</ng-template>\r\n","import { ChangeDetectionStrategy, Component, OnInit } from '@angular/core';\r\nimport { FormControl } from '@angular/forms';\r\nimport { marker as _ } from '@biesbjerg/ngx-translate-extract-marker';\r\nimport {\r\n DataService,\r\n Dialog,\r\n GetChannelsQuery,\r\n NotificationService,\r\n ProductVariantFragment,\r\n} from '@vendure/admin-ui/core';\r\nimport { combineLatest, from, Observable } from 'rxjs';\r\nimport { map, startWith } from 'rxjs/operators';\r\n\r\ntype Channel = GetChannelsQuery['channels'][number];\r\n\r\n@Component({\r\n selector: 'vdr-assign-products-to-channel-dialog',\r\n templateUrl: './assign-products-to-channel-dialog.component.html',\r\n styleUrls: ['./assign-products-to-channel-dialog.component.scss'],\r\n changeDetection: ChangeDetectionStrategy.OnPush,\r\n})\r\nexport class AssignProductsToChannelDialogComponent implements OnInit, Dialog<any> {\r\n selectedChannel: Channel | null | undefined;\r\n currentChannel: Channel;\r\n availableChannels: Channel[];\r\n resolveWith: (result?: any) => void;\r\n variantsPreview$: Observable<Array<{ id: string; name: string; price: number; pricePreview: number }>>;\r\n priceFactorControl = new FormControl(1);\r\n selectedChannelIdControl = new FormControl();\r\n\r\n // assigned by ModalService.fromComponent() call\r\n productIds: string[];\r\n productVariantIds: string[] | undefined;\r\n currentChannelIds: string[];\r\n\r\n get isProductVariantMode(): boolean {\r\n return this.productVariantIds != null;\r\n }\r\n\r\n constructor(private dataService: DataService, private notificationService: NotificationService) {}\r\n\r\n ngOnInit() {\r\n const activeChannelId$ = this.dataService.client\r\n .userStatus()\r\n .mapSingle(({ userStatus }) => userStatus.activeChannelId);\r\n const allChannels$ = this.dataService.settings.getChannels().mapSingle(data => data.channels);\r\n\r\n combineLatest(activeChannelId$, allChannels$).subscribe(([activeChannelId, channels]) => {\r\n // tslint:disable-next-line:no-non-null-assertion\r\n this.currentChannel = channels.find(c => c.id === activeChannelId)!;\r\n this.availableChannels = channels;\r\n });\r\n\r\n this.selectedChannelIdControl.valueChanges.subscribe(ids => {\r\n this.selectChannel(ids);\r\n });\r\n\r\n this.variantsPreview$ = combineLatest(\r\n from(this.getTopVariants(10)),\r\n this.priceFactorControl.valueChanges.pipe(startWith(1)),\r\n ).pipe(\r\n map(([variants, factor]) => {\r\n return variants.map(v => ({\r\n id: v.id,\r\n name: v.name,\r\n price: v.price,\r\n pricePreview: v.price * +factor,\r\n }));\r\n }),\r\n );\r\n }\r\n\r\n selectChannel(channelIds: string[]) {\r\n this.selectedChannel = this.availableChannels.find(c => c.id === channelIds[0]);\r\n }\r\n\r\n assign() {\r\n const selectedChannel = this.selectedChannel;\r\n if (selectedChannel) {\r\n if (!this.isProductVariantMode) {\r\n this.dataService.product\r\n .assignProductsToChannel({\r\n channelId: selectedChannel.id,\r\n productIds: this.productIds,\r\n priceFactor: +this.priceFactorControl.value,\r\n })\r\n .subscribe(() => {\r\n this.notificationService.success(_('catalog.assign-product-to-channel-success'), {\r\n channel: selectedChannel.code,\r\n count: this.productIds.length,\r\n });\r\n this.resolveWith(true);\r\n });\r\n } else if (this.productVariantIds) {\r\n this.dataService.product\r\n .assignVariantsToChannel({\r\n channelId: selectedChannel.id,\r\n productVariantIds: this.productVariantIds,\r\n priceFactor: +this.priceFactorControl.value,\r\n })\r\n .subscribe(() => {\r\n this.notificationService.success(_('catalog.assign-variant-to-channel-success'), {\r\n channel: selectedChannel.code,\r\n // tslint:disable-next-line:no-non-null-assertion\r\n count: this.productVariantIds!.length,\r\n });\r\n this.resolveWith(true);\r\n });\r\n }\r\n }\r\n }\r\n\r\n cancel() {\r\n this.resolveWith();\r\n }\r\n\r\n private async getTopVariants(take: number): Promise<ProductVariantFragment[]> {\r\n const variants: ProductVariantFragment[] = [];\r\n\r\n for (let i = 0; i < this.productIds.length && variants.length < take; i++) {\r\n const productVariants = await this.dataService.product\r\n .getProduct(this.productIds[i], { take: this.isProductVariantMode ? undefined : take })\r\n .mapSingle(({ product }) => {\r\n const _variants = product ? product.variantList.items : [];\r\n return _variants.filter(v =>\r\n this.isProductVariantMode ? this.productVariantIds?.includes(v.id) : true,\r\n );\r\n })\r\n .toPromise();\r\n variants.push(...(productVariants || []));\r\n }\r\n return variants.slice(0, take);\r\n }\r\n}\r\n","/**\r\n * @description\r\n * Like String.prototype.replace(), but replaces the last instance\r\n * rather than the first.\r\n */\r\nexport function replaceLast(target: string | undefined | null, search: string, replace: string): string {\r\n if (!target) {\r\n return '';\r\n }\r\n const lastIndex = target.lastIndexOf(search);\r\n if (lastIndex === -1) {\r\n return target;\r\n }\r\n const head = target.substr(0, lastIndex);\r\n const tail = target.substr(lastIndex).replace(search, replace);\r\n return head + tail;\r\n}\r\n","import { Injectable } from '@angular/core';\r\nimport {\r\n CreateProductInput,\r\n CreateProductVariantInput,\r\n DataService,\r\n DeletionResult,\r\n FacetWithValuesFragment,\r\n findTranslation,\r\n GetProductWithVariantsQuery,\r\n LanguageCode,\r\n UpdateProductInput,\r\n UpdateProductMutation,\r\n UpdateProductOptionInput,\r\n UpdateProductVariantInput,\r\n UpdateProductVariantsMutation,\r\n} from '@vendure/admin-ui/core';\r\nimport { normalizeString } from '@vendure/common/lib/normalize-string';\r\nimport { notNullOrUndefined } from '@vendure/common/lib/shared-utils';\r\nimport { forkJoin, Observable, of, throwError } from 'rxjs';\r\nimport { map, mergeMap, shareReplay, switchMap } from 'rxjs/operators';\r\n\r\nimport { CreateProductVariantsConfig } from '../../components/generate-product-variants/generate-product-variants.component';\r\n\r\nimport { replaceLast } from './replace-last';\r\n\r\n/**\r\n * Handles the logic for making the API calls to perform CRUD operations on a Product and its related\r\n * entities. This logic was extracted out of the component because it became too large and hard to follow.\r\n */\r\n@Injectable({\r\n providedIn: 'root',\r\n})\r\nexport class ProductDetailService {\r\n constructor(private dataService: DataService) {}\r\n\r\n getTaxCategories() {\r\n return this.dataService.settings\r\n .getTaxCategories()\r\n .mapSingle(data => data.taxCategories)\r\n .pipe(shareReplay(1));\r\n }\r\n\r\n createProductWithVariants(\r\n input: CreateProductInput,\r\n createVariantsConfig: CreateProductVariantsConfig,\r\n languageCode: LanguageCode,\r\n ) {\r\n const createProduct$ = this.dataService.product.createProduct(input);\r\n const nonEmptyOptionGroups = createVariantsConfig.groups.filter(g => 0 < g.values.length);\r\n const createOptionGroups$ = this.createProductOptionGroups(nonEmptyOptionGroups, languageCode);\r\n\r\n return forkJoin(createProduct$, createOptionGroups$).pipe(\r\n mergeMap(([{ createProduct }, optionGroups]) => {\r\n const addOptionsToProduct$ = optionGroups.length\r\n ? forkJoin(\r\n optionGroups.map(optionGroup => {\r\n return this.dataService.product.addOptionGroupToProduct({\r\n productId: createProduct.id,\r\n optionGroupId: optionGroup.id,\r\n });\r\n }),\r\n )\r\n : of([]);\r\n return addOptionsToProduct$.pipe(\r\n map(() => {\r\n return { createProduct, optionGroups };\r\n }),\r\n );\r\n }),\r\n mergeMap(({ createProduct, optionGroups }) => {\r\n const variants = createVariantsConfig.variants.map(v => {\r\n const optionIds = optionGroups.length\r\n ? v.optionValues.map((optionName, index) => {\r\n const option = optionGroups[index].options.find(o => o.name === optionName);\r\n if (!option) {\r\n throw new Error(\r\n `Could not find a matching ProductOption \"${optionName}\" when creating variant`,\r\n );\r\n }\r\n return option.id;\r\n })\r\n : [];\r\n return {\r\n ...v,\r\n optionIds,\r\n };\r\n });\r\n const options = optionGroups.map(og => og.options).reduce((flat, o) => [...flat, ...o], []);\r\n return this.createProductVariants(createProduct, variants, options, languageCode);\r\n }),\r\n );\r\n }\r\n\r\n createProductOptionGroups(groups: Array<{ name: string; values: string[] }>, languageCode: LanguageCode) {\r\n return groups.length\r\n ? forkJoin(\r\n groups.map(c => {\r\n return this.dataService.product\r\n .createProductOptionGroups({\r\n code: normalizeString(c.name, '-'),\r\n translations: [{ languageCode, name: c.name }],\r\n options: c.values.map(v => ({\r\n code: normalizeString(v, '-'),\r\n translations: [{ languageCode, name: v }],\r\n })),\r\n })\r\n .pipe(map(data => data.createProductOptionGroup));\r\n }),\r\n )\r\n : of([]);\r\n }\r\n\r\n createProductVariants(\r\n product: { name: string; id: string },\r\n variantData: Array<{ price: number; sku: string; stock: number; optionIds: string[] }>,\r\n options: Array<{ id: string; name: string }>,\r\n languageCode: LanguageCode,\r\n ) {\r\n const variants: CreateProductVariantInput[] = variantData.map(v => {\r\n const name = options.length\r\n ? `${product.name} ${v.optionIds\r\n .map(id => options.find(o => o.id === id))\r\n .filter(notNullOrUndefined)\r\n .map(o => o.name)\r\n .join(' ')}`\r\n : product.name;\r\n return {\r\n productId: product.id,\r\n price: v.price,\r\n sku: v.sku,\r\n stockOnHand: v.stock,\r\n translations: [\r\n {\r\n languageCode,\r\n name,\r\n },\r\n ],\r\n optionIds: v.optionIds,\r\n };\r\n });\r\n return this.dataService.product.createProductVariants(variants).pipe(\r\n map(({ createProductVariants }) => ({\r\n createProductVariants,\r\n productId: product.id,\r\n })),\r\n );\r\n }\r\n\r\n updateProduct(updateOptions: {\r\n product: NonNullable<GetProductWithVariantsQuery['product']>;\r\n languageCode: LanguageCode;\r\n autoUpdate: boolean;\r\n productInput?: UpdateProductInput;\r\n variantsInput?: UpdateProductVariantInput[];\r\n }) {\r\n const { product, languageCode, autoUpdate, productInput, variantsInput } = updateOptions;\r\n const updateOperations: Array<Observable<UpdateProductMutation | UpdateProductVariantsMutation>> = [];\r\n const updateVariantsInput = variantsInput || [];\r\n\r\n const variants$ = autoUpdate\r\n ? this.dataService.product\r\n .getProductVariants({}, product.id)\r\n .mapSingle(({ productVariants }) => productVariants.items)\r\n : of([]);\r\n\r\n return variants$.pipe(\r\n mergeMap(variants => {\r\n if (productInput) {\r\n updateOperations.push(this.dataService.product.updateProduct(productInput));\r\n const productOldName = findTranslation(product, languageCode)?.name ?? '';\r\n const productNewName = findTranslation(productInput, languageCode)?.name;\r\n if (productNewName && productOldName !== productNewName && autoUpdate) {\r\n for (const variant of variants) {\r\n const currentVariantName = findTranslation(variant, languageCode)?.name || '';\r\n let variantInput: UpdateProductVariantInput;\r\n const existingVariantInput = updateVariantsInput.find(i => i.id === variant.id);\r\n if (existingVariantInput) {\r\n variantInput = existingVariantInput;\r\n } else {\r\n variantInput = {\r\n id: variant.id,\r\n translations: [{ languageCode, name: currentVariantName }],\r\n };\r\n updateVariantsInput.push(variantInput);\r\n }\r\n const variantTranslation = findTranslation(variantInput, languageCode);\r\n if (variantTranslation) {\r\n if (variantTranslation.name) {\r\n variantTranslation.name = replaceLast(\r\n variantTranslation.name,\r\n productOldName,\r\n productNewName,\r\n );\r\n } else {\r\n // The variant translation was falsy, which occurs\r\n // when defining the product name for a new translation\r\n // language that had not yet been defined.\r\n variantTranslation.name = [\r\n productNewName,\r\n ...variant.options.map(o => o.name),\r\n ].join(' ');\r\n }\r\n }\r\n }\r\n }\r\n }\r\n if (updateVariantsInput.length) {\r\n updateOperations.push(\r\n this.dataService.product.updateProductVariants(updateVariantsInput),\r\n );\r\n }\r\n return forkJoin(updateOperations);\r\n }),\r\n );\r\n }\r\n\r\n updateProductOption(\r\n input: UpdateProductOptionInput & { autoUpdate: boolean },\r\n product: NonNullable<GetProductWithVariantsQuery['product']>,\r\n languageCode: LanguageCode,\r\n ) {\r\n const variants$ = input.autoUpdate\r\n ? this.dataService.product\r\n .getProductVariants({}, product.id)\r\n .mapSingle(({ productVariants }) => productVariants.items)\r\n : of([]);\r\n\r\n return variants$.pipe(\r\n mergeMap(variants => {\r\n let updateProductVariantNames$: Observable<any> = of([]);\r\n if (input.autoUpdate) {\r\n // Update any ProductVariants' names which include the option name\r\n let oldOptionName: string | undefined;\r\n const newOptionName = findTranslation(input, languageCode)?.name;\r\n if (!newOptionName) {\r\n updateProductVariantNames$ = of([]);\r\n }\r\n const variantsToUpdate: UpdateProductVariantInput[] = [];\r\n for (const variant of variants) {\r\n if (variant.options.map(o => o.id).includes(input.id)) {\r\n if (!oldOptionName) {\r\n oldOptionName = findTranslation(\r\n variant.options.find(o => o.id === input.id),\r\n languageCode,\r\n )?.name;\r\n }\r\n const variantName = findTranslation(variant, languageCode)?.name || '';\r\n if (oldOptionName && newOptionName && variantName.includes(oldOptionName)) {\r\n variantsToUpdate.push({\r\n id: variant.id,\r\n translations: [\r\n {\r\n languageCode,\r\n name: replaceLast(variantName, oldOptionName, newOptionName),\r\n },\r\n ],\r\n });\r\n }\r\n }\r\n }\r\n if (variantsToUpdate.length) {\r\n updateProductVariantNames$ =\r\n this.dataService.product.updateProductVariants(variantsToUpdate);\r\n }\r\n }\r\n return this.dataService.product\r\n .updateProductOption(input)\r\n .pipe(mergeMap(() => updateProductVariantNames$));\r\n }),\r\n );\r\n }\r\n\r\n deleteProductVariant(id: string, productId: string) {\r\n return this.dataService.product.deleteProductVariant(id).pipe(\r\n switchMap(result => {\r\n if (result.deleteProductVariant.result === DeletionResult.DELETED) {\r\n return this.dataService.product.getProduct(productId).single$;\r\n } else {\r\n return throwError(result.deleteProductVariant.message);\r\n }\r\n }),\r\n );\r\n }\r\n}\r\n","import { switchMap } from './switchMap';\nimport { isFunction } from '../util/isFunction';\nexport function switchMapTo(innerObservable, resultSelector) {\n return isFunction(resultSelector) ? switchMap(() => innerObservable, resultSelector) : switchMap(() => innerObservable);\n}\n","<div class=\"input-wrapper\" [class.focus]=\"isFocussed\" (click)=\"textArea.focus()\">\r\n <div class=\"chips\" *ngIf=\"0 < optionValues.length\">\r\n <vdr-chip\r\n *ngFor=\"let option of optionValues; last as isLast; index as i\"\r\n [icon]=\"option.locked ? 'lock' : 'times'\"\r\n [class.selected]=\"isLast && lastSelected\"\r\n [class.locked]=\"option.locked\"\r\n [colorFrom]=\"groupName\"\r\n (iconClick)=\"removeOption(option)\"\r\n >\r\n <span [hidden]=\"editingIndex !== i\">\r\n <input\r\n #editNameInput\r\n type=\"text\"\r\n [ngModel]=\"option.name\"\r\n (blur)=\"updateOption(i, $event)\"\r\n (click)=\"$event.cancelBubble = true\"\r\n />\r\n </span>\r\n <span\r\n class=\"option-name\"\r\n [class.editable]=\"!option.locked && !option.id\"\r\n (click)=\"editName(i, $event)\" [hidden]=\"editingIndex === i\">{{ option.name }}</span>\r\n </vdr-chip>\r\n </div>\r\n <textarea\r\n #textArea\r\n (keyup)=\"handleKey($event)\"\r\n (focus)=\"isFocussed = true\"\r\n (blur)=\"handleBlur()\"\r\n [(ngModel)]=\"input\"\r\n [disabled]=\"disabled\"\r\n ></textarea>\r\n</div>\r\n","import {\r\n ChangeDetectionStrategy,\r\n ChangeDetectorRef,\r\n Component,\r\n ElementRef,\r\n EventEmitter,\r\n forwardRef,\r\n Input,\r\n OnChanges,\r\n OnInit,\r\n Output,\r\n Provider,\r\n QueryList,\r\n SimpleChanges,\r\n ViewChild,\r\n ViewChildren,\r\n} from '@angular/core';\r\nimport { ControlValueAccessor, NG_VALUE_ACCESSOR } from '@angular/forms';\r\nimport { unique } from '@vendure/common/lib/unique';\r\n\r\nexport const OPTION_VALUE_INPUT_VALUE_ACCESSOR: Provider = {\r\n provide: NG_VALUE_ACCESSOR,\r\n useExisting: forwardRef(() => OptionValueInputComponent),\r\n multi: true,\r\n};\r\n\r\ninterface Option {\r\n id?: string;\r\n name: string;\r\n locked: boolean;\r\n}\r\n\r\n@Component({\r\n selector: 'vdr-option-value-input',\r\n templateUrl: './option-value-input.component.html',\r\n styleUrls: ['./option-value-input.component.scss'],\r\n changeDetection: ChangeDetectionStrategy.Default,\r\n providers: [OPTION_VALUE_INPUT_VALUE_ACCESSOR],\r\n})\r\nexport class OptionValueInputComponent implements ControlValueAccessor {\r\n @Input() groupName = '';\r\n @ViewChild('textArea', { static: true }) textArea: ElementRef<HTMLTextAreaElement>;\r\n @ViewChildren('editNameInput', { read: ElementRef }) nameInputs: QueryList<ElementRef>;\r\n @Input() options: Option[];\r\n @Output() add = new EventEmitter<Option>();\r\n @Output() remove = new EventEmitter<Option>();\r\n @Output() edit = new EventEmitter<{ index: number; option: Option }>();\r\n @Input() disabled = false;\r\n input = '';\r\n isFocussed = false;\r\n lastSelected = false;\r\n formValue: Option[];\r\n editingIndex = -1;\r\n onChangeFn: (value: any) => void;\r\n onTouchFn: (value: any) => void;\r\n\r\n get optionValues(): Option[] {\r\n return this.formValue ?? this.options ?? [];\r\n }\r\n\r\n constructor(private changeDetector: ChangeDetectorRef) {}\r\n\r\n registerOnChange(fn: any): void {\r\n this.onChangeFn = fn;\r\n }\r\n\r\n registerOnTouched(fn: any): void {\r\n this.onTouchFn = fn;\r\n }\r\n\r\n setDisabledState(isDisabled: boolean): void {\r\n this.disabled = isDisabled;\r\n this.changeDetector.markForCheck();\r\n }\r\n\r\n writeValue(obj: any): void {\r\n this.formValue = obj || [];\r\n }\r\n\r\n focus() {\r\n this.textArea.nativeElement.focus();\r\n }\r\n\r\n editName(index: number, event: MouseEvent) {\r\n const optionValue = this.optionValues[index];\r\n if (!optionValue.locked && !optionValue.id) {\r\n event.cancelBubble = true;\r\n this.editingIndex = index;\r\n const input = this.nameInputs.get(index)?.nativeElement;\r\n setTimeout(() => input?.focus());\r\n }\r\n }\r\n\r\n updateOption(index: number, event: InputEvent) {\r\n const optionValue = this.optionValues[index];\r\n const newName = (event.target as HTMLInputElement).value;\r\n if (optionValue) {\r\n if (newName) {\r\n optionValue.name = newName;\r\n this.edit.emit({ index, option: optionValue });\r\n }\r\n this.editingIndex = -1;\r\n }\r\n }\r\n\r\n removeOption(option: Option) {\r\n if (!option.locked) {\r\n if (this.formValue) {\r\n this.formValue = this.formValue?.filter(o => o.name !== option.name);\r\n this.onChangeFn(this.formValue);\r\n } else {\r\n this.remove.emit(option);\r\n }\r\n }\r\n }\r\n\r\n handleKey(event: KeyboardEvent) {\r\n switch (event.key) {\r\n case ',':\r\n case 'Enter':\r\n this.addOptionValue();\r\n event.preventDefault();\r\n break;\r\n case 'Backspace':\r\n if (this.lastSelected) {\r\n this.removeLastOption();\r\n this.lastSelected = false;\r\n } else if (this.input === '') {\r\n this.lastSelected = true;\r\n }\r\n break;\r\n default:\r\n this.lastSelected = false;\r\n }\r\n }\r\n\r\n handleBlur() {\r\n this.isFocussed = false;\r\n this.addOptionValue();\r\n }\r\n\r\n private addOptionValue() {\r\n const options = this.parseInputIntoOptions(this.input).filter(option => {\r\n // do not add an option with the same name\r\n // as an existing option\r\n const existing = this.options ?? this.formValue;\r\n return !existing?.find(o => o?.name === option.name);\r\n });\r\n if (!this.formValue && this.options) {\r\n for (const option of options) {\r\n this.add.emit(option);\r\n }\r\n } else {\r\n this.formValue = unique([...this.formValue, ...options]);\r\n this.onChangeFn(this.formValue);\r\n }\r\n this.input = '';\r\n }\r\n\r\n private parseInputIntoOptions(input: string): Option[] {\r\n return input\r\n .split(/[,\\n]/)\r\n .map(s => s.trim())\r\n .filter(s => s !== '')\r\n .map(s => ({ name: s, locked: false }));\r\n }\r\n\r\n private removeLastOption() {\r\n if (this.optionValues.length) {\r\n const option = this.optionValues[this.optionValues.length - 1];\r\n this.removeOption(option);\r\n }\r\n }\r\n}\r\n","<div *ngFor=\"let group of optionGroups\" class=\"option-groups\">\r\n <div class=\"name\">\r\n <label>{{ 'catalog.option' | translate }}</label>\r\n <input\r\n #optionGroupName\r\n placeholder=\"e.g. Size\"\r\n clrInput\r\n [(ngModel)]=\"group.name\"\r\n name=\"name\"\r\n required\r\n (keydown.enter)=\"handleEnter($event, optionValueInputComponent)\"\r\n />\r\n </div>\r\n <div class=\"values\">\r\n <label>{{ 'catalog.option-values' | translate }}</label>\r\n <vdr-option-value-input\r\n #optionValueInputComponent\r\n [(ngModel)]=\"group.values\"\r\n (ngModelChange)=\"generateVariants()\"\r\n (edit)=\"generateVariants()\"\r\n [groupName]=\"group.name\"\r\n [disabled]=\"group.name === ''\"\r\n ></vdr-option-value-input>\r\n </div>\r\n <div class=\"remove-group\">\r\n <button\r\n class=\"btn btn-icon btn-warning-outline\"\r\n [title]=\"'catalog.remove-option' | translate\"\r\n (click)=\"removeOption(group.name)\"\r\n >\r\n <clr-icon shape=\"trash\"></clr-icon>\r\n </button>\r\n </div>\r\n</div>\r\n<button class=\"btn btn-primary-outline btn-sm\" (click)=\"addOption()\">\r\n <clr-icon shape=\"plus\"></clr-icon>\r\n {{ 'catalog.add-option' | translate }}\r\n</button>\r\n\r\n<div class=\"variants-preview\">\r\n <table class=\"table\">\r\n <thead>\r\n <tr>\r\n <th *ngIf=\"1 < variants.length\">{{ 'common.create' | translate }}</th>\r\n <th *ngIf=\"1 < variants.length\">{{ 'catalog.variant' | translate }}</th>\r\n <th>{{ 'catalog.sku' | translate }}</th>\r\n <th>{{ 'catalog.price' | translate }}</th>\r\n <th>{{ 'catalog.stock-on-hand' | translate }}</th>\r\n </tr>\r\n </thead>\r\n <tr\r\n *ngFor=\"let variant of variants; trackBy: trackByFn\"\r\n [class.disabled]=\"!variantFormValues[variant.id].enabled\"\r\n >\r\n <td *ngIf=\"1 < variants.length\">\r\n <input\r\n type=\"checkbox\"\r\n (change)=\"onFormChange()\"\r\n [(ngModel)]=\"variantFormValues[variant.id].enabled\"\r\n clrCheckbox\r\n />\r\n </td>\r\n <td *ngIf=\"1 < variants.length\">\r\n {{ variant.values.join(' ') }}\r\n </td>\r\n <td>\r\n <clr-input-container>\r\n <input\r\n clrInput\r\n type=\"text\"\r\n (change)=\"onFormChange()\"\r\n [(ngModel)]=\"variantFormValues[variant.id].sku\"\r\n [placeholder]=\"'catalog.sku' | translate\"\r\n />\r\n </clr-input-container>\r\n </td>\r\n <td>\r\n <clr-input-container>\r\n <vdr-currency-input\r\n clrInput\r\n [(ngModel)]=\"variantFormValues[variant.id].price\"\r\n (ngModelChange)=\"onFormChange()\"\r\n [currencyCode]=\"currencyCode\"\r\n ></vdr-currency-input>\r\n </clr-input-container>\r\n </td>\r\n <td>\r\n <clr-input-container>\r\n <input\r\n clrInput\r\n type=\"number\"\r\n [(ngModel)]=\"variantFormValues[variant.id].stock\"\r\n (change)=\"onFormChange()\"\r\n min=\"0\"\r\n step=\"1\"\r\n />\r\n </clr-input-container>\r\n </td>\r\n </tr>\r\n </table>\r\n</div>\r\n","import { Component, ElementRef, EventEmitter, OnInit, Output, QueryList, ViewChildren } from '@angular/core';\r\nimport { CurrencyCode, DataService } from '@vendure/admin-ui/core';\r\nimport { generateAllCombinations } from '@vendure/common/lib/shared-utils';\r\n\r\nimport { OptionValueInputComponent } from '../option-value-input/option-value-input.component';\r\n\r\nconst DEFAULT_VARIANT_CODE = '__DEFAULT_VARIANT__';\r\nexport type CreateVariantValues = {\r\n optionValues: string[];\r\n enabled: boolean;\r\n sku: string;\r\n price: number;\r\n stock: number;\r\n};\r\nexport type CreateProductVariantsConfig = {\r\n groups: Array<{ name: string; values: string[] }>;\r\n variants: CreateVariantValues[];\r\n};\r\n\r\n@Component({\r\n selector: 'vdr-generate-product-variants',\r\n templateUrl: './generate-product-variants.component.html',\r\n styleUrls: ['./generate-product-variants.component.scss'],\r\n})\r\nexport class GenerateProductVariantsComponent implements OnInit {\r\n @Output() variantsChange = new EventEmitter<CreateProductVariantsConfig>();\r\n @ViewChildren('optionGroupName', { read: ElementRef }) groupNameInputs: QueryList<ElementRef>;\r\n optionGroups: Array<{ name: string; values: Array<{ name: string; locked: boolean }> }> = [];\r\n currencyCode: CurrencyCode;\r\n variants: Array<{ id: string; values: string[] }>;\r\n variantFormValues: { [id: string]: CreateVariantValues } = {};\r\n constructor(private dataService: DataService) {}\r\n\r\n ngOnInit() {\r\n this.dataService.settings.getActiveChannel().single$.subscribe(data => {\r\n this.currencyCode = data.activeChannel.currencyCode;\r\n });\r\n\r\n this.generateVariants();\r\n }\r\n\r\n addOption() {\r\n this.optionGroups.push({ name: '', values: [] });\r\n const index = this.optionGroups.length - 1;\r\n setTimeout(() => {\r\n const input = this.groupNameInputs.get(index)?.nativeElement;\r\n input?.focus();\r\n });\r\n }\r\n\r\n removeOption(name: string) {\r\n this.optionGroups = this.optionGroups.filter(g => g.name !== name);\r\n this.generateVariants();\r\n }\r\n\r\n generateVariants() {\r\n const totalValuesCount = this.optionGroups.reduce((sum, group) => sum + group.values.length, 0);\r\n const groups = totalValuesCount\r\n ? this.optionGroups.map(g => g.values.map(v => v.name))\r\n : [[DEFAULT_VARIANT_CODE]];\r\n this.variants = generateAllCombinations(groups).map(values => ({ id: values.join('|'), values }));\r\n\r\n this.variants.forEach(variant => {\r\n if (!this.variantFormValues[variant.id]) {\r\n this.variantFormValues[variant.id] = {\r\n optionValues: variant.values,\r\n enabled: true,\r\n price: this.copyFromDefault(variant.id, 'price', 0),\r\n sku: this.copyFromDefault(variant.id, 'sku', ''),\r\n stock: this.copyFromDefault(variant.id, 'stock', 0),\r\n };\r\n }\r\n });\r\n this.onFormChange();\r\n }\r\n\r\n trackByFn(index: number, variant: { name: string; values: string[] }) {\r\n return variant.values.join('|');\r\n }\r\n\r\n handleEnter(event: KeyboardEvent, optionValueInputComponent: OptionValueInputComponent) {\r\n event.preventDefault();\r\n event.stopPropagation();\r\n optionValueInputComponent.focus();\r\n }\r\n\r\n onFormChange() {\r\n const variantsToCreate = this.variants.map(v => this.variantFormValues[v.id]).filter(v => v.enabled);\r\n this.variantsChange.emit({\r\n groups: this.optionGroups.map(og => ({ name: og.name, values: og.values.map(v => v.name) })),\r\n variants: variantsToCreate,\r\n });\r\n }\r\n\r\n private copyFromDefault<T extends keyof CreateVariantValues>(\r\n variantId: string,\r\n prop: T,\r\n value: CreateVariantValues[T],\r\n ): CreateVariantValues[T] {\r\n return variantId !== DEFAULT_VARIANT_CODE\r\n ? this.variantFormValues[DEFAULT_VARIANT_CODE][prop]\r\n : value;\r\n }\r\n}\r\n","<table class=\"table\">\r\n <thead>\r\n <tr>\r\n <th></th>\r\n <th>{{ 'common.name' | translate }}</th>\r\n <th>{{ 'catalog.sku' | translate }}</th>\r\n <ng-container *ngFor=\"let optionGroup of optionGroups | sort: 'id'\">\r\n <th>{{ optionGroup.name }}</th>\r\n </ng-container>\r\n <th>{{ 'catalog.price' | translate }}</th>\r\n <th>{{ 'catalog.stock-on-hand' | translate }}</th>\r\n <th>{{ 'common.enabled' | translate }}</th>\r\n </tr>\r\n </thead>\r\n <tbody>\r\n <tr *ngFor=\"let variant of variants | paginate: paginationConfig; index as i; trackBy: trackByFn\">\r\n <ng-container *ngIf=\"formGroupMap.get(variant.id) as formGroup\" [formGroup]=\"formGroup\">\r\n <td class=\"left align-middle\" [class.disabled]=\"!formGroup.get('enabled')!.value\">\r\n <div class=\"card-img\">\r\n <div class=\"featured-asset\">\r\n <img\r\n *ngIf=\"getFeaturedAsset(variant) as featuredAsset; else placeholder\"\r\n [src]=\"featuredAsset | assetPreview: 'tiny'\"\r\n />\r\n <ng-template #placeholder>\r\n <div class=\"placeholder\">\r\n <clr-icon shape=\"image\" size=\"48\"></clr-icon>\r\n </div>\r\n </ng-template>\r\n </div>\r\n </div>\r\n </td>\r\n <td class=\"left align-middle\" [class.disabled]=\"!formGroup.get('enabled')!.value\">\r\n <clr-input-container>\r\n <input\r\n clrInput\r\n type=\"text\"\r\n formControlName=\"name\"\r\n [readonly]=\"!(updatePermission | hasPermission)\"\r\n [placeholder]=\"'common.name' | translate\"\r\n />\r\n </clr-input-container>\r\n </td>\r\n <td class=\"left align-middle\" [class.disabled]=\"!formGroup.get('enabled')!.value\">\r\n <clr-input-container>\r\n <input\r\n clrInput\r\n type=\"text\"\r\n formControlName=\"sku\"\r\n [readonly]=\"!(updatePermission | hasPermission)\"\r\n [placeholder]=\"'catalog.sku' | translate\"\r\n />\r\n </clr-input-container>\r\n </td>\r\n <ng-container *ngFor=\"let option of variant.options | sort: 'groupId'\">\r\n <td\r\n class=\"left align-middle\"\r\n [class.disabled]=\"!formGroup.get('enabled')!.value\"\r\n [style.color]=\"optionGroupName(option.groupId) | stringToColor\"\r\n >\r\n {{ option.name }}\r\n </td>\r\n </ng-container>\r\n <td class=\"left align-middle price\" [class.disabled]=\"!formGroup.get('enabled')!.value\">\r\n <clr-input-container>\r\n <vdr-currency-input\r\n *ngIf=\"!channelPriceIncludesTax\"\r\n clrInput\r\n [currencyCode]=\"variant.currencyCode\"\r\n [readonly]=\"!(updatePermission | hasPermission)\"\r\n formControlName=\"price\"\r\n ></vdr-currency-input>\r\n <vdr-currency-input\r\n *ngIf=\"channelPriceIncludesTax\"\r\n clrInput\r\n [currencyCode]=\"variant.currencyCode\"\r\n [readonly]=\"!(updatePermission | hasPermission)\"\r\n formControlName=\"priceWithTax\"\r\n ></vdr-currency-input>\r\n </clr-input-container>\r\n </td>\r\n <td class=\"left align-middle stock\" [class.disabled]=\"!formGroup.get('enabled')!.value\">\r\n <clr-input-container>\r\n <input\r\n clrInput\r\n type=\"number\"\r\n min=\"0\"\r\n step=\"1\"\r\n formControlName=\"stockOnHand\"\r\n [readonly]=\"!(updatePermission | hasPermission)\"\r\n />\r\n </clr-input-container>\r\n </td>\r\n <td class=\"left align-middle stock\" [class.disabled]=\"!formGroup.get('enabled')!.value\">\r\n <clr-toggle-wrapper>\r\n <input\r\n type=\"checkbox\"\r\n clrToggle\r\n name=\"enabled\"\r\n formControlName=\"enabled\"\r\n [vdrDisabled]=\"!(updatePermission | hasPermission)\"\r\n />\r\n </clr-toggle-wrapper>\r\n </td>\r\n </ng-container>\r\n </tr>\r\n </tbody>\r\n</table>\r\n","import {\r\n ChangeDetectionStrategy,\r\n ChangeDetectorRef,\r\n Component,\r\n Input,\r\n OnDestroy,\r\n OnInit,\r\n} from '@angular/core';\r\nimport { FormArray, FormGroup } from '@angular/forms';\r\nimport { Permission, ProductDetailFragment, ProductVariantFragment } from '@vendure/admin-ui/core';\r\nimport { Subscription } from 'rxjs';\r\nimport { debounceTime, distinctUntilChanged, map } from 'rxjs/operators';\r\n\r\nimport { PaginationConfig, SelectedAssets } from '../product-detail/product-detail.types';\r\n\r\n@Component({\r\n selector: 'vdr-product-variants-table',\r\n templateUrl: './product-variants-table.component.html',\r\n styleUrls: ['./product-variants-table.component.scss'],\r\n changeDetection: ChangeDetectionStrategy.OnPush,\r\n})\r\nexport class ProductVariantsTableComponent implements OnInit, OnDestroy {\r\n @Input('productVariantsFormArray') formArray: FormArray;\r\n @Input() variants: ProductVariantFragment[];\r\n @Input() paginationConfig: PaginationConfig;\r\n @Input() channelPriceIncludesTax: boolean;\r\n @Input() optionGroups: ProductDetailFragment['optionGroups'];\r\n @Input() pendingAssetChanges: { [variantId: string]: SelectedAssets };\r\n formGroupMap = new Map<string, FormGroup>();\r\n readonly updatePermission = [Permission.UpdateCatalog, Permission.UpdateProduct];\r\n private subscription: Subscription;\r\n\r\n constructor(private changeDetector: ChangeDetectorRef) {}\r\n\r\n ngOnInit() {\r\n this.subscription = this.formArray.valueChanges\r\n .pipe(\r\n map(value => value.length),\r\n debounceTime(1),\r\n distinctUntilChanged(),\r\n )\r\n .subscribe(() => {\r\n this.buildFormGroupMap();\r\n });\r\n\r\n this.buildFormGroupMap();\r\n }\r\n\r\n ngOnDestroy() {\r\n if (this.subscription) {\r\n this.subscription.unsubscribe();\r\n }\r\n }\r\n\r\n trackByFn(index: number, item: any) {\r\n if ((item as any).id != null) {\r\n return (item as any).id;\r\n } else {\r\n return index;\r\n }\r\n }\r\n\r\n getFeaturedAsset(variant: ProductVariantFragment) {\r\n return this.pendingAssetChanges[variant.id]?.featuredAsset || variant.featuredAsset;\r\n }\r\n\r\n optionGroupName(optionGroupId: string): string | undefined {\r\n const group = this.optionGroups.find(g => g.id === optionGroupId);\r\n return group && group.name;\r\n }\r\n\r\n private buildFormGroupMap() {\r\n this.formGroupMap.clear();\r\n for (const controlGroup of this.formArray.controls) {\r\n this.formGroupMap.set(controlGroup.value.id, controlGroup as FormGroup);\r\n }\r\n this.changeDetector.markForCheck();\r\n }\r\n}\r\n","<ng-template vdrDialogTitle>{{ 'catalog.update-product-option' | translate }}</ng-template>\r\n<vdr-form-field [label]=\"'catalog.option-name' | translate\" for=\"name\">\r\n <input\r\n id=\"name\"\r\n type=\"text\"\r\n #nameInput=\"ngModel\"\r\n [(ngModel)]=\"name\"\r\n required\r\n (input)=\"updateCode($event.target.value)\"\r\n />\r\n</vdr-form-field>\r\n<vdr-form-field [label]=\"'common.code' | translate\" for=\"code\">\r\n <input id=\"code\" type=\"text\" #codeInput=\"ngModel\" required [(ngModel)]=\"code\" pattern=\"[a-z0-9_-]+\" />\r\n</vdr-form-field>\r\n<clr-checkbox-wrapper>\r\n <input type=\"checkbox\" clrCheckbox [(ngModel)]=\"updateVariantName\" />\r\n <label>{{ 'catalog.auto-update-option-variant-name' | translate }}</label>\r\n</clr-checkbox-wrapper>\r\n<section *ngIf=\"customFields.length\">\r\n <label>{{ 'common.custom-fields' | translate }}</label>\r\n <vdr-tabbed-custom-fields\r\n entityName=\"ProductOption\"\r\n [customFields]=\"customFields\"\r\n [customFieldsFormGroup]=\"customFieldsForm\"\r\n [readonly]=\"!(['UpdateCatalog', 'UpdateProduct'] | hasPermission)\"\r\n ></vdr-tabbed-custom-fields>\r\n</section>\r\n\r\n<ng-template vdrDialogButtons>\r\n <button type=\"button\" class=\"btn\" (click)=\"cancel()\">{{ 'common.cancel' | translate }}</button>\r\n <button\r\n type=\"submit\"\r\n (click)=\"update()\"\r\n [disabled]=\"\r\n nameInput.invalid ||\r\n codeInput.invalid ||\r\n (nameInput.pristine && codeInput.pristine && customFieldsForm.pristine)\r\n \"\r\n class=\"btn btn-primary\"\r\n >\r\n {{ 'catalog.update-product-option' | translate }}\r\n </button>\r\n</ng-template>\r\n","import { ChangeDetectionStrategy, Component, OnInit } from '@angular/core';\r\nimport { FormControl, FormGroup } from '@angular/forms';\r\nimport {\r\n CustomFieldConfig,\r\n LanguageCode,\r\n ProductVariantFragment,\r\n UpdateProductOptionInput,\r\n} from '@vendure/admin-ui/core';\r\nimport { createUpdatedTranslatable } from '@vendure/admin-ui/core';\r\nimport { Dialog } from '@vendure/admin-ui/core';\r\nimport { normalizeString } from '@vendure/common/lib/normalize-string';\r\n\r\n@Component({\r\n selector: 'vdr-update-product-option-dialog',\r\n templateUrl: './update-product-option-dialog.component.html',\r\n styleUrls: ['./update-product-option-dialog.component.scss'],\r\n changeDetection: ChangeDetectionStrategy.OnPush,\r\n})\r\nexport class UpdateProductOptionDialogComponent\r\n implements Dialog<UpdateProductOptionInput & { autoUpdate: boolean }>, OnInit\r\n{\r\n resolveWith: (result?: UpdateProductOptionInput & { autoUpdate: boolean }) => void;\r\n updateVariantName = true;\r\n // Provided by caller\r\n productOption: ProductVariantFragment['options'][number];\r\n activeLanguage: LanguageCode;\r\n name: string;\r\n code: string;\r\n customFields: CustomFieldConfig[];\r\n codeInputTouched = false;\r\n customFieldsForm: FormGroup;\r\n\r\n ngOnInit(): void {\r\n const currentTranslation = this.productOption.translations.find(\r\n t => t.languageCode === this.activeLanguage,\r\n );\r\n this.name = currentTranslation?.name ?? '';\r\n this.code = this.productOption.code;\r\n this.customFieldsForm = new FormGroup({});\r\n if (this.customFields) {\r\n const cfCurrentTranslation =\r\n (currentTranslation && (currentTranslation as any).customFields) || {};\r\n\r\n for (const fieldDef of this.customFields) {\r\n const key = fieldDef.name;\r\n const value =\r\n fieldDef.type === 'localeString'\r\n ? cfCurrentTranslation[key]\r\n : (this.productOption as any).customFields[key];\r\n this.customFieldsForm.addControl(fieldDef.name, new FormControl(value));\r\n }\r\n }\r\n }\r\n\r\n update() {\r\n const result = createUpdatedTranslatable({\r\n translatable: this.productOption,\r\n languageCode: this.activeLanguage,\r\n updatedFields: {\r\n code: this.code,\r\n name: this.name,\r\n customFields: this.customFieldsForm.value,\r\n },\r\n customFieldConfig: this.customFields,\r\n defaultTranslation: {\r\n languageCode: this.activeLanguage,\r\n name: '',\r\n },\r\n });\r\n this.resolveWith({ ...result, autoUpdate: this.updateVariantName });\r\n }\r\n\r\n cancel() {\r\n this.resolveWith();\r\n }\r\n\r\n updateCode(nameValue: string) {\r\n if (!this.codeInputTouched && !this.productOption.code) {\r\n this.code = normalizeString(nameValue, '-');\r\n }\r\n }\r\n}\r\n","<label class=\"clr-control-label\">{{ 'catalog.taxes' | translate }}</label>\r\n<div *ngIf=\"priceIncludesTax\" class=\"value\">\r\n {{ 'catalog.price-includes-tax-at' | translate: { rate: taxRate$ | async } }}\r\n</div>\r\n<div *ngIf=\"!priceIncludesTax\" class=\"value\">\r\n {{\r\n 'catalog.price-with-tax-in-default-zone'\r\n | translate: { price: grossPrice$ | async | localeCurrency: currencyCode, rate: taxRate$ | async }\r\n }}\r\n</div>\r\n","import { ChangeDetectionStrategy, Component, Input, OnChanges, OnInit, SimpleChanges } from '@angular/core';\r\nimport { DataService } from '@vendure/admin-ui/core';\r\nimport { BehaviorSubject, combineLatest, Observable, Subject } from 'rxjs';\r\nimport { map } from 'rxjs/operators';\r\n\r\n@Component({\r\n selector: 'vdr-variant-price-detail',\r\n templateUrl: './variant-price-detail.component.html',\r\n styleUrls: ['./variant-price-detail.component.scss'],\r\n changeDetection: ChangeDetectionStrategy.OnPush,\r\n})\r\nexport class VariantPriceDetailComponent implements OnInit, OnChanges {\r\n @Input() priceIncludesTax: boolean;\r\n @Input() price: number;\r\n @Input() currencyCode: string;\r\n @Input() taxCategoryId: string;\r\n\r\n grossPrice$: Observable<number>;\r\n taxRate$: Observable<number>;\r\n\r\n private priceChange$ = new BehaviorSubject<number>(0);\r\n private taxCategoryIdChange$ = new BehaviorSubject<string>('');\r\n\r\n constructor(private dataService: DataService) {}\r\n\r\n ngOnInit() {\r\n const taxRates$ = this.dataService.settings\r\n .getTaxRatesSimple(999, 0, 'cache-first')\r\n .mapStream(data => data.taxRates.items);\r\n const activeChannel$ = this.dataService.settings\r\n .getActiveChannel('cache-first')\r\n .refetchOnChannelChange()\r\n .mapStream(data => data.activeChannel);\r\n\r\n this.taxRate$ = combineLatest(activeChannel$, taxRates$, this.taxCategoryIdChange$).pipe(\r\n map(([channel, taxRates, taxCategoryId]) => {\r\n const defaultTaxZone = channel.defaultTaxZone;\r\n if (!defaultTaxZone) {\r\n return 0;\r\n }\r\n const applicableRate = taxRates.find(\r\n taxRate => taxRate.zone.id === defaultTaxZone.id && taxRate.category.id === taxCategoryId,\r\n );\r\n\r\n if (!applicableRate) {\r\n return 0;\r\n }\r\n return applicableRate.value;\r\n }),\r\n );\r\n\r\n this.grossPrice$ = combineLatest(this.taxRate$, this.priceChange$).pipe(\r\n map(([taxRate, price]) => {\r\n return Math.round(price * ((100 + taxRate) / 100));\r\n }),\r\n );\r\n }\r\n\r\n ngOnChanges(changes: SimpleChanges): void {\r\n if ('price' in changes) {\r\n this.priceChange$.next(changes.price.currentValue);\r\n }\r\n if ('taxCategoryId' in changes) {\r\n this.taxCategoryIdChange$.next(changes.taxCategoryId.currentValue);\r\n }\r\n }\r\n}\r\n","<div class=\"variants-list\">\r\n <div\r\n class=\"variant-container card\"\r\n *ngFor=\"\r\n let variant of variants | paginate: paginationConfig || { itemsPerPage: 10, currentPage: 1 };\r\n trackBy: trackById;\r\n let i = index\r\n \"\r\n [class.disabled]=\"!formGroupMap.get(variant.id)?.get('enabled')?.value\"\r\n >\r\n <ng-container *ngIf=\"formGroupMap.get(variant.id) as formGroup\" [formGroup]=\"formGroup\">\r\n <div class=\"card-block header-row\">\r\n <div class=\"details\">\r\n <vdr-title-input class=\"sku\" [readonly]=\"!(updatePermission | hasPermission)\">\r\n <clr-input-container>\r\n <input\r\n clrInput\r\n type=\"text\"\r\n formControlName=\"sku\"\r\n [readonly]=\"!(updatePermission | hasPermission)\"\r\n [placeholder]=\"'catalog.sku' | translate\"\r\n />\r\n </clr-input-container>\r\n </vdr-title-input>\r\n <vdr-title-input class=\"name\" [readonly]=\"!(updatePermission | hasPermission)\">\r\n <clr-input-container>\r\n <input\r\n clrInput\r\n type=\"text\"\r\n formControlName=\"name\"\r\n [readonly]=\"!(updatePermission | hasPermission)\"\r\n [placeholder]=\"'common.name' | translate\"\r\n />\r\n </clr-input-container>\r\n </vdr-title-input>\r\n </div>\r\n <div class=\"right-controls\">\r\n <clr-toggle-wrapper *vdrIfPermissions=\"updatePermission\">\r\n <input type=\"checkbox\" clrToggle name=\"enabled\" formControlName=\"enabled\" />\r\n <label>{{ 'common.enabled' | translate }}</label>\r\n </clr-toggle-wrapper>\r\n </div>\r\n </div>\r\n <div class=\"card-block\">\r\n <div class=\"variant-body\">\r\n <div class=\"assets\">\r\n <vdr-assets\r\n [compact]=\"true\"\r\n [assets]=\"pendingAssetChanges[variant.id]?.assets || variant.assets\"\r\n [featuredAsset]=\"\r\n pendingAssetChanges[variant.id]?.featuredAsset || variant.featuredAsset\r\n \"\r\n [updatePermissions]=\"updatePermission\"\r\n (change)=\"onAssetChange(variant.id, $event)\"\r\n ></vdr-assets>\r\n </div>\r\n <div class=\"variant-form-inputs\">\r\n <div class=\"standard-fields\">\r\n <div class=\"variant-form-input-row\">\r\n <div class=\"tax-category\">\r\n <clr-select-container\r\n *vdrIfPermissions=\"updatePermission; else taxCategoryLabel\"\r\n >\r\n <label>{{ 'catalog.tax-category' | translate }}</label>\r\n <select clrSelect name=\"options\" formControlName=\"taxCategoryId\">\r\n <option\r\n *ngFor=\"let taxCategory of taxCategories\"\r\n [value]=\"taxCategory.id\"\r\n >\r\n {{ taxCategory.name }}\r\n </option>\r\n </select>\r\n </clr-select-container>\r\n <ng-template #taxCategoryLabel>\r\n <label class=\"clr-control-label\">{{\r\n 'catalog.tax-category' | translate\r\n }}</label>\r\n <div class=\"tax-category-label\">\r\n {{ getTaxCategoryName(formGroup) }}\r\n </div>\r\n </ng-template>\r\n </div>\r\n <div class=\"price\">\r\n <clr-input-container>\r\n <label>{{ 'catalog.price' | translate }}</label>\r\n <vdr-currency-input\r\n *ngIf=\"!channelPriceIncludesTax\"\r\n clrInput\r\n [currencyCode]=\"variant.currencyCode\"\r\n [readonly]=\"!(updatePermission | hasPermission)\"\r\n formControlName=\"price\"\r\n ></vdr-currency-input>\r\n <vdr-currency-input\r\n *ngIf=\"channelPriceIncludesTax\"\r\n clrInput\r\n [currencyCode]=\"variant.currencyCode\"\r\n [readonly]=\"!(updatePermission | hasPermission)\"\r\n formControlName=\"priceWithTax\"\r\n ></vdr-currency-input>\r\n </clr-input-container>\r\n </div>\r\n <vdr-variant-price-detail\r\n [price]=\"formGroup.get('price')!.value\"\r\n [currencyCode]=\"variant.currencyCode\"\r\n [priceIncludesTax]=\"channelPriceIncludesTax\"\r\n [taxCategoryId]=\"formGroup.get('taxCategoryId')!.value\"\r\n ></vdr-variant-price-detail>\r\n </div>\r\n <div class=\"variant-form-input-row\">\r\n <clr-select-container *vdrIfPermissions=\"updatePermission\">\r\n <label\r\n >{{ 'catalog.track-inventory' | translate }}\r\n <vdr-help-tooltip\r\n [content]=\"'catalog.track-inventory-tooltip' | translate\"\r\n ></vdr-help-tooltip>\r\n </label>\r\n <select clrSelect name=\"options\" formControlName=\"trackInventory\">\r\n <option [value]=\"GlobalFlag.TRUE\">\r\n {{ 'catalog.track-inventory-true' | translate }}\r\n </option>\r\n <option [value]=\"GlobalFlag.FALSE\">\r\n {{ 'catalog.track-inventory-false' | translate }}\r\n </option>\r\n <option [value]=\"GlobalFlag.INHERIT\">\r\n {{ 'catalog.track-inventory-inherit' | translate }}\r\n </option>\r\n </select>\r\n </clr-select-container>\r\n <clr-input-container>\r\n <label\r\n >{{ 'catalog.stock-on-hand' | translate }}\r\n <vdr-help-tooltip\r\n [content]=\"'catalog.stock-on-hand-tooltip' | translate\"\r\n ></vdr-help-tooltip\r\n ></label>\r\n <input\r\n [class.inventory-untracked]=\"inventoryIsNotTracked(formGroup)\"\r\n clrInput\r\n type=\"number\"\r\n [min]=\"getStockOnHandMinValue(formGroup)\"\r\n step=\"1\"\r\n formControlName=\"stockOnHand\"\r\n [readonly]=\"!(updatePermission | hasPermission)\"\r\n [vdrDisabled]=\"inventoryIsNotTracked(formGroup)\"\r\n />\r\n </clr-input-container>\r\n <div [class.inventory-untracked]=\"inventoryIsNotTracked(formGroup)\">\r\n <label class=\"clr-control-label\"\r\n >{{ 'catalog.stock-allocated' | translate }}\r\n <vdr-help-tooltip\r\n [content]=\"'catalog.stock-allocated-tooltip' | translate\"\r\n ></vdr-help-tooltip\r\n ></label>\r\n <div class=\"value\">\r\n {{ variant.stockAllocated }}\r\n </div>\r\n </div>\r\n <div [class.inventory-untracked]=\"inventoryIsNotTracked(formGroup)\">\r\n <label class=\"clr-control-label\"\r\n >{{ 'catalog.stock-saleable' | translate }}\r\n <vdr-help-tooltip\r\n [content]=\"'catalog.stock-saleable-tooltip' | translate\"\r\n ></vdr-help-tooltip\r\n ></label>\r\n <div class=\"value\">\r\n {{ getSaleableStockLevel(variant) }}\r\n </div>\r\n </div>\r\n </div>\r\n\r\n <div class=\"variant-form-input-row\">\r\n <div\r\n class=\"out-of-stock-threshold-wrapper\"\r\n [class.inventory-untracked]=\"inventoryIsNotTracked(formGroup)\"\r\n >\r\n <label class=\"clr-control-label\"\r\n >{{ 'catalog.out-of-stock-threshold' | translate\r\n }}<vdr-help-tooltip\r\n [content]=\"'catalog.out-of-stock-threshold-tooltip' | translate\"\r\n ></vdr-help-tooltip\r\n ></label>\r\n <div class=\"flex\">\r\n <clr-input-container>\r\n <input\r\n clrInput\r\n type=\"number\"\r\n [formControl]=\"formGroup.get('outOfStockThreshold')\"\r\n [readonly]=\"!(updatePermission | hasPermission)\"\r\n [vdrDisabled]=\"\r\n formGroup.get('useGlobalOutOfStockThreshold')?.value !==\r\n false || inventoryIsNotTracked(formGroup)\r\n \"\r\n />\r\n </clr-input-container>\r\n <clr-toggle-wrapper>\r\n <input\r\n type=\"checkbox\"\r\n clrToggle\r\n name=\"useGlobalOutOfStockThreshold\"\r\n formControlName=\"useGlobalOutOfStockThreshold\"\r\n [vdrDisabled]=\"\r\n !(updatePermission | hasPermission) ||\r\n inventoryIsNotTracked(formGroup)\r\n \"\r\n />\r\n <label\r\n >{{ 'catalog.use-global-value' | translate }} ({{\r\n globalOutOfStockThreshold\r\n }})</label\r\n >\r\n </clr-toggle-wrapper>\r\n </div>\r\n </div>\r\n </div>\r\n </div>\r\n <div class=\"custom-fields\">\r\n <div class=\"variant-form-input-row\">\r\n <section formGroupName=\"customFields\" *ngIf=\"customFields.length\">\r\n <vdr-tabbed-custom-fields\r\n entityName=\"ProductVariant\"\r\n [customFields]=\"customFields\"\r\n [compact]=\"true\"\r\n [customFieldsFormGroup]=\"formGroup.get('customFields')\"\r\n [readonly]=\"!(updatePermission | hasPermission)\"\r\n ></vdr-tabbed-custom-fields>\r\n </section>\r\n </div>\r\n </div>\r\n </div>\r\n </div>\r\n </div>\r\n <div class=\"card-block\">\r\n <div class=\"options-facets\">\r\n <vdr-entity-info [entity]=\"variant\"></vdr-entity-info>\r\n <div *ngIf=\"variant.options.length\">\r\n <div class=\"options\">\r\n <vdr-chip\r\n *ngFor=\"let option of variant.options | sort: 'groupId'\"\r\n [colorFrom]=\"optionGroupName(option.groupId)\"\r\n [invert]=\"true\"\r\n (iconClick)=\"editOption(option)\"\r\n [icon]=\"(updatePermission | hasPermission) && 'pencil'\"\r\n >\r\n <span class=\"option-group-name\">{{ optionGroupName(option.groupId) }}</span>\r\n {{ optionName(option) }}\r\n </vdr-chip>\r\n <a [routerLink]=\"['./', 'options']\" class=\"btn btn-link btn-sm\"\r\n >{{ 'catalog.edit-options' | translate }}...</a\r\n >\r\n </div>\r\n </div>\r\n <div class=\"flex-spacer\"></div>\r\n <div class=\"facets\">\r\n <vdr-facet-value-chip\r\n *ngFor=\"let facetValue of currentOrPendingFacetValues(variant)\"\r\n [facetValue]=\"facetValue\"\r\n [removable]=\"updatePermission | hasPermission\"\r\n (remove)=\"removeFacetValue(variant, facetValue.id)\"\r\n ></vdr-facet-value-chip>\r\n <button\r\n *vdrIfPermissions=\"updatePermission\"\r\n class=\"btn btn-sm btn-secondary\"\r\n (click)=\"selectFacetValue(variant)\"\r\n >\r\n <clr-icon shape=\"plus\"></clr-icon>\r\n {{ 'catalog.add-facets' | translate }}\r\n </button>\r\n </div>\r\n </div>\r\n </div>\r\n <ng-container *vdrIfMultichannel>\r\n <div class=\"card-block\" *vdrIfDefaultChannelActive>\r\n <div class=\"flex channel-assignment\">\r\n <ng-container *ngFor=\"let channel of variant.channels\">\r\n <vdr-chip\r\n *ngIf=\"!isDefaultChannel(channel.code)\"\r\n icon=\"times-circle\"\r\n [title]=\"'catalog.remove-from-channel' | translate: { channelCode: channel.code }\"\r\n (iconClick)=\"\r\n removeFromChannel.emit({ channelId: channel.id, variant: variant })\r\n \"\r\n >\r\n <vdr-channel-badge [channelCode]=\"channel.code\"></vdr-channel-badge>\r\n {{ channel.code | channelCodeToLabel }}\r\n </vdr-chip>\r\n </ng-container>\r\n <button class=\"btn btn-sm\" (click)=\"assignToChannel.emit(variant)\">\r\n <clr-icon shape=\"layers\"></clr-icon>\r\n {{ 'catalog.assign-to-channel' | translate }}\r\n </button>\r\n </div>\r\n </div>\r\n </ng-container>\r\n </ng-container>\r\n </div>\r\n</div>\r\n","import {\n ChangeDetectionStrategy,\n ChangeDetectorRef,\n Component,\n EventEmitter,\n Input,\n OnDestroy,\n OnInit,\n Output,\n} from '@angular/core';\nimport { FormArray, FormGroup } from '@angular/forms';\nimport {\n CustomFieldConfig,\n DataService,\n FacetValueFragment,\n FacetWithValuesFragment,\n GlobalFlag,\n LanguageCode,\n ModalService,\n Permission,\n ProductDetailFragment,\n ProductOptionFragment,\n ProductVariantFragment,\n TaxCategory,\n UpdateProductOptionInput,\n} from '@vendure/admin-ui/core';\nimport { DEFAULT_CHANNEL_CODE } from '@vendure/common/lib/shared-constants';\nimport { unique } from '@vendure/common/lib/unique';\nimport { Subscription } from 'rxjs';\nimport { debounceTime, distinctUntilChanged, map } from 'rxjs/operators';\n\nimport { ApplyFacetDialogComponent } from '../apply-facet-dialog/apply-facet-dialog.component';\nimport { AssetChange } from '../assets/assets.component';\nimport { PaginationConfig, SelectedAssets, VariantFormValue } from '../product-detail/product-detail.types';\nimport { UpdateProductOptionDialogComponent } from '../update-product-option-dialog/update-product-option-dialog.component';\n\nexport interface VariantAssetChange extends AssetChange {\n variantId: string;\n}\n\n@Component({\n selector: 'vdr-product-variants-list',\n templateUrl: './product-variants-list.component.html',\n styleUrls: ['./product-variants-list.component.scss'],\n changeDetection: ChangeDetectionStrategy.OnPush,\n})\nexport class ProductVariantsListComponent implements OnInit, OnDestroy {\n @Input('productVariantsFormArray') formArray: FormArray;\n @Input() variants: ProductVariantFragment[];\n @Input() paginationConfig: PaginationConfig;\n @Input() channelPriceIncludesTax: boolean;\n @Input() taxCategories: TaxCategory[];\n @Input() optionGroups: ProductDetailFragment['optionGroups'];\n @Input() customFields: CustomFieldConfig[];\n @Input() customOptionFields: CustomFieldConfig[];\n @Input() activeLanguage: LanguageCode;\n @Input() pendingAssetChanges: { [variantId: string]: SelectedAssets };\n @Input() pendingFacetValueChanges: { [variantId: string]: ProductVariantFragment['facetValues'] };\n @Output() assignToChannel = new EventEmitter<ProductVariantFragment>();\n @Output() removeFromChannel = new EventEmitter<{\n channelId: string;\n variant: ProductVariantFragment;\n }>();\n @Output() assetChange = new EventEmitter<VariantAssetChange>();\n @Output() selectionChange = new EventEmitter<string[]>();\n @Output() updateProductOption = new EventEmitter<UpdateProductOptionInput & { autoUpdate: boolean }>();\n selectedVariantIds: string[] = [];\n formGroupMap = new Map<string, FormGroup>();\n GlobalFlag = GlobalFlag;\n globalTrackInventory: boolean;\n globalOutOfStockThreshold: number;\n readonly updatePermission = [Permission.UpdateCatalog, Permission.UpdateProduct];\n private subscription: Subscription;\n\n constructor(\n private changeDetector: ChangeDetectorRef,\n private modalService: ModalService,\n private dataService: DataService,\n ) {}\n\n ngOnInit() {\n this.dataService.settings.getGlobalSettings('cache-first').single$.subscribe(({ globalSettings }) => {\n this.globalTrackInventory = globalSettings.trackInventory;\n this.globalOutOfStockThreshold = globalSettings.outOfStockThreshold;\n this.changeDetector.markForCheck();\n });\n this.subscription = this.formArray.valueChanges.subscribe(() => this.changeDetector.markForCheck());\n\n this.subscription.add(\n this.formArray.valueChanges\n .pipe(\n map(value => value.length),\n debounceTime(1),\n distinctUntilChanged(),\n )\n .subscribe(() => {\n this.buildFormGroupMap();\n }),\n );\n\n this.buildFormGroupMap();\n }\n\n ngOnDestroy() {\n if (this.subscription) {\n this.subscription.unsubscribe();\n }\n }\n\n isDefaultChannel(channelCode: string): boolean {\n return channelCode === DEFAULT_CHANNEL_CODE;\n }\n\n trackById(index: number, item: ProductVariantFragment) {\n return item.id;\n }\n\n inventoryIsNotTracked(formGroup: FormGroup): boolean {\n const trackInventory = formGroup.get('trackInventory')?.value;\n return (\n trackInventory === GlobalFlag.FALSE ||\n (trackInventory === GlobalFlag.INHERIT && this.globalTrackInventory === false)\n );\n }\n\n getTaxCategoryName(group: FormGroup): string {\n const control = group.get(['taxCategoryId']);\n if (control && this.taxCategories) {\n const match = this.taxCategories.find(t => t.id === control.value);\n return match ? match.name : '';\n }\n return '';\n }\n\n getStockOnHandMinValue(variant: FormGroup) {\n const effectiveOutOfStockThreshold = variant.get('useGlobalOutOfStockThreshold')?.value\n ? this.globalOutOfStockThreshold\n : variant.get('outOfStockThreshold')?.value;\n return effectiveOutOfStockThreshold;\n }\n\n getSaleableStockLevel(variant: ProductVariantFragment) {\n const effectiveOutOfStockThreshold = variant.useGlobalOutOfStockThreshold\n ? this.globalOutOfStockThreshold\n : variant.outOfStockThreshold;\n return variant.stockOnHand - variant.stockAllocated - effectiveOutOfStockThreshold;\n }\n\n areAllSelected(): boolean {\n return !!this.variants && this.selectedVariantIds.length === this.variants.length;\n }\n\n onAssetChange(variantId: string, event: AssetChange) {\n this.assetChange.emit({\n variantId,\n ...event,\n });\n const index = this.formArray.controls.findIndex(c => c.value.id === variantId);\n this.formArray.at(index).markAsDirty();\n }\n\n toggleSelectAll() {\n if (this.areAllSelected()) {\n this.selectedVariantIds = [];\n } else {\n this.selectedVariantIds = this.variants.map(v => v.id);\n }\n this.selectionChange.emit(this.selectedVariantIds);\n }\n\n toggleSelectVariant(variantId: string) {\n const index = this.selectedVariantIds.indexOf(variantId);\n if (-1 < index) {\n this.selectedVariantIds.splice(index, 1);\n } else {\n this.selectedVariantIds.push(variantId);\n }\n this.selectionChange.emit(this.selectedVariantIds);\n }\n\n optionGroupName(optionGroupId: string): string | undefined {\n const group = this.optionGroups.find(g => g.id === optionGroupId);\n if (group) {\n const translation =\n group?.translations.find(t => t.languageCode === this.activeLanguage) ??\n group.translations[0];\n return translation.name;\n }\n }\n\n optionName(option: ProductOptionFragment) {\n const translation =\n option.translations.find(t => t.languageCode === this.activeLanguage) ?? option.translations[0];\n return translation.name;\n }\n\n currentOrPendingFacetValues(variant: ProductVariantFragment) {\n return this.pendingFacetValueChanges[variant.id] ?? variant.facetValues;\n }\n\n selectFacetValue(variant: ProductVariantFragment) {\n return this.modalService\n .fromComponent(ApplyFacetDialogComponent, {\n size: 'md',\n closable: true,\n })\n .subscribe(facetValues => {\n if (facetValues) {\n const existingFacetValueIds = variant ? variant.facetValues.map(fv => fv.id) : [];\n const variantFormGroup = this.formArray.controls.find(c => c.value.id === variant.id);\n if (variantFormGroup) {\n const uniqueFacetValueIds = unique([\n ...existingFacetValueIds,\n ...facetValues.map(fv => fv.id),\n ]);\n variantFormGroup.patchValue({ facetValueIds: uniqueFacetValueIds });\n variantFormGroup.markAsDirty();\n if (!this.pendingFacetValueChanges[variant.id]) {\n this.pendingFacetValueChanges[variant.id] = variant.facetValues.slice(0);\n }\n this.pendingFacetValueChanges[variant.id].push(...facetValues);\n }\n this.changeDetector.markForCheck();\n }\n });\n }\n\n removeFacetValue(variant: ProductVariantFragment, facetValueId: string) {\n const formGroup = this.formGroupMap.get(variant.id);\n if (formGroup) {\n const newValue = (formGroup.value as VariantFormValue).facetValueIds.filter(\n id => id !== facetValueId,\n );\n formGroup.patchValue({\n facetValueIds: newValue,\n });\n formGroup.markAsDirty();\n if (!this.pendingFacetValueChanges[variant.id]) {\n this.pendingFacetValueChanges[variant.id] = variant.facetValues.slice(0);\n }\n this.pendingFacetValueChanges[variant.id] = this.pendingFacetValueChanges[variant.id].filter(\n fv => fv.id !== facetValueId,\n );\n }\n }\n\n isVariantSelected(variantId: string): boolean {\n return -1 < this.selectedVariantIds.indexOf(variantId);\n }\n\n editOption(option: ProductVariantFragment['options'][number]) {\n this.modalService\n .fromComponent(UpdateProductOptionDialogComponent, {\n size: 'md',\n locals: {\n productOption: option,\n activeLanguage: this.activeLanguage,\n customFields: this.customOptionFields,\n },\n })\n .subscribe(result => {\n if (result) {\n this.updateProductOption.emit(result);\n }\n });\n }\n\n private buildFormGroupMap() {\n this.formGroupMap.clear();\n for (const controlGroup of this.formArray.controls) {\n this.formGroupMap.set(controlGroup.value.id, controlGroup as FormGroup);\n }\n this.changeDetector.markForCheck();\n }\n\n private getFacetValueIds(id: string): string[] {\n const formValue: VariantFormValue = this.formGroupMap.get(id)?.value;\n return formValue.facetValueIds;\n }\n}\n","<vdr-action-bar>\r\n <vdr-ab-left>\r\n <div class=\"flex clr-flex-row\">\r\n <vdr-entity-info [entity]=\"entity$ | async\"></vdr-entity-info>\r\n <clr-toggle-wrapper *vdrIfPermissions=\"['UpdateCatalog', 'UpdateProduct']\">\r\n <input\r\n type=\"checkbox\"\r\n clrToggle\r\n name=\"enabled\"\r\n [formControl]=\"detailForm.get(['product', 'enabled'])\"\r\n />\r\n <label>{{ 'common.enabled' | translate }}</label>\r\n </clr-toggle-wrapper>\r\n </div>\r\n <vdr-language-selector\r\n [disabled]=\"isNew$ | async\"\r\n [availableLanguageCodes]=\"availableLanguages$ | async\"\r\n [currentLanguageCode]=\"languageCode$ | async\"\r\n (languageCodeChange)=\"setLanguage($event)\"\r\n ></vdr-language-selector>\r\n </vdr-ab-left>\r\n\r\n <vdr-ab-right>\r\n <vdr-action-bar-items locationId=\"product-detail\"></vdr-action-bar-items>\r\n <button\r\n class=\"btn btn-primary\"\r\n *ngIf=\"isNew$ | async; else updateButton\"\r\n (click)=\"create()\"\r\n [disabled]=\"detailForm.invalid || detailForm.pristine || !variantsToCreateAreValid()\"\r\n >\r\n {{ 'common.create' | translate }}\r\n </button>\r\n <ng-template #updateButton>\r\n <button\r\n *vdrIfPermissions=\"['UpdateCatalog', 'UpdateProduct']\"\r\n class=\"btn btn-primary\"\r\n (click)=\"save()\"\r\n [disabled]=\"\r\n (detailForm.invalid || detailForm.pristine) && !assetsChanged() && !variantAssetsChanged()\r\n \"\r\n >\r\n {{ 'common.update' | translate }}\r\n </button>\r\n </ng-template>\r\n </vdr-ab-right>\r\n</vdr-action-bar>\r\n\r\n<form class=\"form\" [formGroup]=\"detailForm\" *ngIf=\"product$ | async as product\">\r\n <button type=\"submit\" hidden x-data=\"prevents enter key from triggering other buttons\"></button>\r\n <clr-tabs>\r\n <clr-tab>\r\n <button clrTabLink (click)=\"navigateToTab('details')\">\r\n {{ 'catalog.product-details' | translate }}\r\n </button>\r\n <clr-tab-content *clrIfActive=\"(activeTab$ | async) === 'details'\">\r\n <div class=\"clr-row\">\r\n <div class=\"clr-col\">\r\n <section class=\"form-block\" formGroupName=\"product\">\r\n <ng-container *ngIf=\"!(isNew$ | async)\">\r\n <ng-container *vdrIfMultichannel>\r\n <vdr-form-item\r\n [label]=\"'common.channels' | translate\"\r\n *vdrIfDefaultChannelActive\r\n >\r\n <div class=\"flex channel-assignment\">\r\n <ng-container *ngFor=\"let channel of productChannels$ | async\">\r\n <vdr-chip\r\n *ngIf=\"!isDefaultChannel(channel.code)\"\r\n icon=\"times-circle\"\r\n (iconClick)=\"removeFromChannel(channel.id)\"\r\n >\r\n <vdr-channel-badge\r\n [channelCode]=\"channel.code\"\r\n ></vdr-channel-badge>\r\n {{ channel.code | channelCodeToLabel }}\r\n </vdr-chip>\r\n </ng-container>\r\n <button class=\"btn btn-sm\" (click)=\"assignToChannel()\">\r\n <clr-icon shape=\"layers\"></clr-icon>\r\n {{ 'catalog.assign-to-channel' | translate }}\r\n </button>\r\n </div>\r\n </vdr-form-item>\r\n </ng-container>\r\n </ng-container>\r\n <vdr-form-field [label]=\"'catalog.product-name' | translate\" for=\"name\">\r\n <input\r\n id=\"name\"\r\n type=\"text\"\r\n formControlName=\"name\"\r\n [readonly]=\"!(['UpdateCatalog', 'UpdateProduct'] | hasPermission)\"\r\n (input)=\"updateSlug($event.target.value)\"\r\n />\r\n </vdr-form-field>\r\n <div\r\n class=\"auto-rename-wrapper\"\r\n [class.visible]=\"\r\n (isNew$ | async) === false && detailForm.get(['product', 'name'])?.dirty\r\n \"\r\n >\r\n <clr-checkbox-wrapper>\r\n <input\r\n clrCheckbox\r\n type=\"checkbox\"\r\n id=\"auto-update\"\r\n formControlName=\"autoUpdateVariantNames\"\r\n />\r\n <label>{{\r\n 'catalog.auto-update-product-variant-name' | translate\r\n }}</label>\r\n </clr-checkbox-wrapper>\r\n </div>\r\n <vdr-form-field\r\n [label]=\"'catalog.slug' | translate\"\r\n for=\"slug\"\r\n [errors]=\"{ pattern: 'catalog.slug-pattern-error' | translate }\"\r\n >\r\n <input\r\n id=\"slug\"\r\n type=\"text\"\r\n formControlName=\"slug\"\r\n [readonly]=\"!(['UpdateCatalog', 'UpdateProduct'] | hasPermission)\"\r\n />\r\n </vdr-form-field>\r\n <vdr-rich-text-editor\r\n formControlName=\"description\"\r\n [readonly]=\"!(['UpdateCatalog', 'UpdateProduct'] | hasPermission)\"\r\n [label]=\"'common.description' | translate\"\r\n ></vdr-rich-text-editor>\r\n\r\n <section formGroupName=\"customFields\" *ngIf=\"customFields.length\">\r\n <label>{{ 'common.custom-fields' | translate }}</label>\r\n <vdr-tabbed-custom-fields\r\n entityName=\"Product\"\r\n [customFields]=\"customFields\"\r\n [customFieldsFormGroup]=\"detailForm.get(['product', 'customFields'])\"\r\n [readonly]=\"!(['UpdateCatalog', 'UpdateProduct'] | hasPermission)\"\r\n ></vdr-tabbed-custom-fields>\r\n </section>\r\n <vdr-custom-detail-component-host\r\n locationId=\"product-detail\"\r\n [entity$]=\"entity$\"\r\n [detailForm]=\"detailForm\"\r\n ></vdr-custom-detail-component-host>\r\n </section>\r\n </div>\r\n <div class=\"clr-col-md-auto\">\r\n <vdr-assets\r\n [assets]=\"assetChanges.assets || product.assets\"\r\n [featuredAsset]=\"assetChanges.featuredAsset || product.featuredAsset\"\r\n [updatePermissions]=\"updatePermissions\"\r\n (change)=\"assetChanges = $event\"\r\n ></vdr-assets>\r\n <div class=\"facets\">\r\n <vdr-facet-value-chip\r\n *ngFor=\"let facetValue of facetValues$ | async\"\r\n [facetValue]=\"facetValue\"\r\n [removable]=\"['UpdateCatalog', 'UpdateProduct'] | hasPermission\"\r\n (remove)=\"removeProductFacetValue(facetValue.id)\"\r\n ></vdr-facet-value-chip>\r\n <button\r\n class=\"btn btn-sm btn-secondary\"\r\n *vdrIfPermissions=\"['UpdateCatalog', 'UpdateProduct']\"\r\n (click)=\"selectProductFacetValue()\"\r\n >\r\n <clr-icon shape=\"plus\"></clr-icon>\r\n {{ 'catalog.add-facets' | translate }}\r\n </button>\r\n </div>\r\n </div>\r\n </div>\r\n\r\n <div *ngIf=\"isNew$ | async\">\r\n <h4>{{ 'catalog.product-variants' | translate }}</h4>\r\n <vdr-generate-product-variants\r\n (variantsChange)=\"createVariantsConfig = $event\"\r\n ></vdr-generate-product-variants>\r\n </div>\r\n </clr-tab-content>\r\n </clr-tab>\r\n <clr-tab *ngIf=\"!(isNew$ | async)\">\r\n <button clrTabLink (click)=\"navigateToTab('variants')\">\r\n {{ 'catalog.product-variants' | translate }}\r\n </button>\r\n <clr-tab-content *clrIfActive=\"(activeTab$ | async) === 'variants'\">\r\n <section class=\"form-block\">\r\n <div class=\"view-mode\">\r\n <div class=\"btn-group\">\r\n <button\r\n class=\"btn btn-secondary-outline\"\r\n (click)=\"variantDisplayMode = 'card'\"\r\n [class.btn-primary]=\"variantDisplayMode === 'card'\"\r\n >\r\n <clr-icon shape=\"list\"></clr-icon>\r\n <span class=\"full-label\">{{ 'catalog.display-variant-cards' | translate }}</span>\r\n </button>\r\n <button\r\n class=\"btn\"\r\n (click)=\"variantDisplayMode = 'table'\"\r\n [class.btn-primary]=\"variantDisplayMode === 'table'\"\r\n >\r\n <clr-icon shape=\"table\"></clr-icon>\r\n <span class=\"full-label\">{{ 'catalog.display-variant-table' | translate }}</span>\r\n </button>\r\n </div>\r\n <div class=\"variant-filter\">\r\n <input\r\n [formControl]=\"filterInput\"\r\n [placeholder]=\"'catalog.filter-by-name-or-sku' | translate\"\r\n />\r\n <button class=\"icon-button\" (click)=\"filterInput.setValue('')\">\r\n <clr-icon shape=\"times\"></clr-icon>\r\n </button>\r\n </div>\r\n <div class=\"flex-spacer\"></div>\r\n <a\r\n *vdrIfPermissions=\"['UpdateCatalog', 'UpdateProduct']\"\r\n [routerLink]=\"['./', 'manage-variants']\"\r\n class=\"btn btn-secondary edit-variants-btn mb0 mr0\"\r\n >\r\n <clr-icon shape=\"add-text\"></clr-icon>\r\n {{ 'catalog.manage-variants' | translate }}\r\n </a>\r\n </div>\r\n\r\n <div class=\"pagination-row mt4\" *ngIf=\"10 < (paginationConfig$ | async)?.totalItems\">\r\n <vdr-items-per-page-controls\r\n [itemsPerPage]=\"itemsPerPage$ | async\"\r\n (itemsPerPageChange)=\"setItemsPerPage($event)\"\r\n ></vdr-items-per-page-controls>\r\n\r\n <vdr-pagination-controls\r\n [id]=\"(paginationConfig$ | async)?.id\"\r\n [currentPage]=\"currentPage$ | async\"\r\n [itemsPerPage]=\"itemsPerPage$ | async\"\r\n (pageChange)=\"setPage($event)\"\r\n ></vdr-pagination-controls>\r\n </div>\r\n\r\n <vdr-product-variants-table\r\n *ngIf=\"variantDisplayMode === 'table'\"\r\n [variants]=\"variants$ | async\"\r\n [paginationConfig]=\"paginationConfig$ | async\"\r\n [optionGroups]=\"product.optionGroups\"\r\n [channelPriceIncludesTax]=\"channelPriceIncludesTax$ | async\"\r\n [productVariantsFormArray]=\"detailForm.get('variants')\"\r\n [pendingAssetChanges]=\"variantAssetChanges\"\r\n ></vdr-product-variants-table>\r\n <vdr-product-variants-list\r\n *ngIf=\"variantDisplayMode === 'card'\"\r\n [variants]=\"variants$ | async\"\r\n [paginationConfig]=\"paginationConfig$ | async\"\r\n [channelPriceIncludesTax]=\"channelPriceIncludesTax$ | async\"\r\n [pendingFacetValueChanges]=\"variantFacetValueChanges\"\r\n [optionGroups]=\"product.optionGroups\"\r\n [productVariantsFormArray]=\"detailForm.get('variants')\"\r\n [taxCategories]=\"taxCategories$ | async\"\r\n [customFields]=\"customVariantFields\"\r\n [customOptionFields]=\"customOptionFields\"\r\n [activeLanguage]=\"languageCode$ | async\"\r\n [pendingAssetChanges]=\"variantAssetChanges\"\r\n (assignToChannel)=\"assignVariantToChannel($event)\"\r\n (removeFromChannel)=\"removeVariantFromChannel($event)\"\r\n (assetChange)=\"variantAssetChange($event)\"\r\n (updateProductOption)=\"updateProductOption($event)\"\r\n (selectionChange)=\"selectedVariantIds = $event\"\r\n ></vdr-product-variants-list>\r\n </section>\r\n <div class=\"pagination-row mt4\" *ngIf=\"10 < (paginationConfig$ | async)?.totalItems\">\r\n <vdr-items-per-page-controls\r\n [itemsPerPage]=\"itemsPerPage$ | async\"\r\n (itemsPerPageChange)=\"setItemsPerPage($event)\"\r\n ></vdr-items-per-page-controls>\r\n\r\n <vdr-pagination-controls\r\n [id]=\"(paginationConfig$ | async)?.id\"\r\n [currentPage]=\"currentPage$ | async\"\r\n [itemsPerPage]=\"itemsPerPage$ | async\"\r\n (pageChange)=\"setPage($event)\"\r\n ></vdr-pagination-controls>\r\n </div>\r\n </clr-tab-content>\r\n </clr-tab>\r\n </clr-tabs>\r\n</form>\r\n","import { Location } from '@angular/common';\nimport { ChangeDetectionStrategy, ChangeDetectorRef, Component, OnDestroy, OnInit } from '@angular/core';\nimport { FormArray, FormBuilder, FormControl, FormGroup, Validators } from '@angular/forms';\nimport { ActivatedRoute, Router } from '@angular/router';\nimport { marker as _ } from '@biesbjerg/ngx-translate-extract-marker';\nimport {\n BaseDetailComponent,\n CreateProductInput,\n createUpdatedTranslatable,\n CustomFieldConfig,\n DataService,\n findTranslation,\n getChannelCodeFromUserStatus,\n GetProductWithVariantsQuery,\n LanguageCode,\n LogicalOperator,\n ModalService,\n NotificationService,\n Permission,\n ProductDetailFragment,\n ProductVariantFragment,\n ServerConfigService,\n TaxCategoryFragment,\n unicodePatternValidator,\n UpdateProductInput,\n UpdateProductMutation,\n UpdateProductOptionInput,\n UpdateProductVariantInput,\n UpdateProductVariantsMutation,\n} from '@vendure/admin-ui/core';\nimport { normalizeString } from '@vendure/common/lib/normalize-string';\nimport { DEFAULT_CHANNEL_CODE } from '@vendure/common/lib/shared-constants';\nimport { notNullOrUndefined } from '@vendure/common/lib/shared-utils';\nimport { unique } from '@vendure/common/lib/unique';\nimport { BehaviorSubject, combineLatest, concat, EMPTY, from, merge, Observable } from 'rxjs';\nimport {\n debounceTime,\n distinctUntilChanged,\n map,\n mergeMap,\n shareReplay,\n skip,\n skipUntil,\n startWith,\n switchMap,\n switchMapTo,\n take,\n takeUntil,\n tap,\n} from 'rxjs/operators';\n\nimport { ProductDetailService } from '../../providers/product-detail/product-detail.service';\nimport { ApplyFacetDialogComponent } from '../apply-facet-dialog/apply-facet-dialog.component';\nimport { AssignProductsToChannelDialogComponent } from '../assign-products-to-channel-dialog/assign-products-to-channel-dialog.component';\nimport { CreateProductVariantsConfig } from '../generate-product-variants/generate-product-variants.component';\nimport { VariantAssetChange } from '../product-variants-list/product-variants-list.component';\n\nimport { PaginationConfig, SelectedAssets, TabName, VariantFormValue } from './product-detail.types';\n\n@Component({\n selector: 'vdr-product-detail',\n templateUrl: './product-detail.component.html',\n styleUrls: ['./product-detail.component.scss'],\n changeDetection: ChangeDetectionStrategy.OnPush,\n})\nexport class ProductDetailComponent\n extends BaseDetailComponent<NonNullable<GetProductWithVariantsQuery['product']>>\n implements OnInit, OnDestroy\n{\n activeTab$: Observable<TabName>;\n product$: Observable<NonNullable<GetProductWithVariantsQuery['product']>>;\n variants$: Observable<ProductVariantFragment[]>;\n taxCategories$: Observable<TaxCategoryFragment[]>;\n customFields: CustomFieldConfig[];\n customVariantFields: CustomFieldConfig[];\n customOptionGroupFields: CustomFieldConfig[];\n customOptionFields: CustomFieldConfig[];\n detailForm: FormGroup;\n filterInput = new FormControl('');\n assetChanges: SelectedAssets = {};\n variantAssetChanges: { [variantId: string]: SelectedAssets } = {};\n variantFacetValueChanges: { [variantId: string]: ProductVariantFragment['facetValues'] } = {};\n productChannels$: Observable<ProductDetailFragment['channels']>;\n facetValues$: Observable<ProductDetailFragment['facetValues']>;\n totalItems$: Observable<number>;\n currentPage$ = new BehaviorSubject(1);\n itemsPerPage$ = new BehaviorSubject(10);\n paginationConfig$: Observable<PaginationConfig>;\n selectedVariantIds: string[] = [];\n variantDisplayMode: 'card' | 'table' = 'card';\n createVariantsConfig: CreateProductVariantsConfig = { groups: [], variants: [] };\n channelPriceIncludesTax$: Observable<boolean>;\n // Used to store all ProductVariants which have been loaded.\n // It is needed when saving changes to variants.\n private productVariantMap = new Map<string, ProductVariantFragment>();\n public readonly updatePermissions = [Permission.UpdateCatalog, Permission.UpdateProduct];\n\n constructor(\n route: ActivatedRoute,\n router: Router,\n serverConfigService: ServerConfigService,\n private productDetailService: ProductDetailService,\n private formBuilder: FormBuilder,\n private modalService: ModalService,\n private notificationService: NotificationService,\n protected dataService: DataService,\n private location: Location,\n private changeDetector: ChangeDetectorRef,\n ) {\n super(route, router, serverConfigService, dataService);\n this.customFields = this.getCustomFieldConfig('Product');\n this.customVariantFields = this.getCustomFieldConfig('ProductVariant');\n this.customOptionGroupFields = this.getCustomFieldConfig('ProductOptionGroup');\n this.customOptionFields = this.getCustomFieldConfig('ProductOption');\n this.detailForm = this.formBuilder.group({\n product: this.formBuilder.group({\n enabled: true,\n name: ['', Validators.required],\n autoUpdateVariantNames: true,\n slug: ['', unicodePatternValidator(/^[\\p{Letter}0-9_-]+$/)],\n description: '',\n facetValueIds: [[]],\n customFields: this.formBuilder.group(\n this.customFields.reduce((hash, field) => ({ ...hash, [field.name]: '' }), {}),\n ),\n }),\n variants: this.formBuilder.array([]),\n });\n }\n\n ngOnInit() {\n this.init();\n this.product$ = this.entity$;\n const filterTerm$ = this.filterInput.valueChanges.pipe(\n startWith(''),\n debounceTime(200),\n shareReplay(),\n tap(() => this.currentPage$.next(1)),\n );\n const initialVariants$ = this.product$.pipe(map(p => p.variantList.items));\n const variantsList$ = combineLatest(filterTerm$, this.currentPage$, this.itemsPerPage$).pipe(\n skipUntil(initialVariants$),\n skip(1),\n debounceTime(100),\n switchMap(([term, currentPage, itemsPerPage]) => {\n return this.dataService.product\n .getProductVariants(\n {\n skip: (currentPage - 1) * itemsPerPage,\n take: itemsPerPage,\n ...(term\n ? { filter: { name: { contains: term }, sku: { contains: term } } }\n : {}),\n filterOperator: LogicalOperator.OR,\n },\n this.id,\n )\n .mapStream(({ productVariants }) => productVariants);\n }),\n shareReplay({ bufferSize: 1, refCount: true }),\n );\n const updatedVariants$ = variantsList$.pipe(map(result => result.items));\n this.variants$ = merge(initialVariants$, updatedVariants$).pipe(\n tap(variants => {\n for (const variant of variants) {\n this.productVariantMap.set(variant.id, variant);\n }\n }),\n );\n this.totalItems$ = merge(\n this.product$.pipe(map(product => product.variantList.totalItems)),\n variantsList$.pipe(map(result => result.totalItems)),\n );\n this.paginationConfig$ = combineLatest(this.totalItems$, this.itemsPerPage$, this.currentPage$).pipe(\n map(([totalItems, itemsPerPage, currentPage]) => ({\n totalItems,\n itemsPerPage,\n currentPage,\n })),\n );\n this.taxCategories$ = this.productDetailService.getTaxCategories().pipe(takeUntil(this.destroy$));\n this.activeTab$ = this.route.paramMap.pipe(map(qpm => qpm.get('tab') as any));\n\n combineLatest(updatedVariants$, this.languageCode$)\n .pipe(takeUntil(this.destroy$))\n .subscribe(([variants, languageCode]) => {\n this.buildVariantFormArray(variants, languageCode);\n });\n\n const productFacetValues$ = this.product$.pipe(map(product => product.facetValues));\n const productGroup = this.getProductFormGroup();\n // tslint:disable-next-line:no-non-null-assertion\n const formFacetValueIdChanges$ = productGroup.get('facetValueIds')!.valueChanges.pipe(\n skip(1),\n distinctUntilChanged(),\n switchMap(ids =>\n this.dataService.facet\n .getFacetValues({ filter: { id: { in: ids } } })\n .mapSingle(({ facetValues }) => facetValues.items),\n ),\n shareReplay(1),\n );\n this.facetValues$ = concat(\n productFacetValues$.pipe(take(1)),\n productFacetValues$.pipe(switchMapTo(formFacetValueIdChanges$)),\n );\n this.productChannels$ = this.product$.pipe(map(p => p.channels));\n this.channelPriceIncludesTax$ = this.dataService.settings\n .getActiveChannel('cache-first')\n .refetchOnChannelChange()\n .mapStream(data => data.activeChannel.pricesIncludeTax)\n .pipe(shareReplay(1));\n }\n\n ngOnDestroy() {\n this.destroy();\n }\n\n navigateToTab(tabName: TabName) {\n this.location.replaceState(\n this.router\n .createUrlTree(['./', { ...this.route.snapshot.params, tab: tabName }], {\n queryParamsHandling: 'merge',\n relativeTo: this.route,\n })\n .toString(),\n );\n }\n\n isDefaultChannel(channelCode: string): boolean {\n return channelCode === DEFAULT_CHANNEL_CODE;\n }\n\n setPage(page: number) {\n this.currentPage$.next(page);\n }\n\n setItemsPerPage(value: string) {\n this.itemsPerPage$.next(+value);\n this.currentPage$.next(1);\n }\n\n assignToChannel() {\n this.productChannels$\n .pipe(\n take(1),\n switchMap(channels => {\n return this.modalService.fromComponent(AssignProductsToChannelDialogComponent, {\n size: 'lg',\n locals: {\n productIds: [this.id],\n currentChannelIds: channels.map(c => c.id),\n },\n });\n }),\n )\n .subscribe();\n }\n\n removeFromChannel(channelId: string) {\n from(getChannelCodeFromUserStatus(this.dataService, channelId))\n .pipe(\n switchMap(({ channelCode }) => {\n return this.modalService.dialog({\n title: _('catalog.remove-product-from-channel'),\n buttons: [\n { type: 'secondary', label: _('common.cancel') },\n {\n type: 'danger',\n label: _('catalog.remove-from-channel'),\n translationVars: { channelCode },\n returnValue: true,\n },\n ],\n });\n }),\n switchMap(response =>\n response\n ? this.dataService.product.removeProductsFromChannel({\n channelId,\n productIds: [this.id],\n })\n : EMPTY,\n ),\n )\n .subscribe(\n () => {\n this.notificationService.success(_('catalog.notify-remove-product-from-channel-success'));\n },\n err => {\n this.notificationService.error(_('catalog.notify-remove-product-from-channel-error'));\n },\n );\n }\n\n assignVariantToChannel(variant: ProductVariantFragment) {\n return this.modalService\n .fromComponent(AssignProductsToChannelDialogComponent, {\n size: 'lg',\n locals: {\n productIds: [this.id],\n productVariantIds: [variant.id],\n currentChannelIds: variant.channels.map(c => c.id),\n },\n })\n .subscribe();\n }\n\n removeVariantFromChannel({ channelId, variant }: { channelId: string; variant: ProductVariantFragment }) {\n from(getChannelCodeFromUserStatus(this.dataService, channelId))\n .pipe(\n switchMap(({ channelCode }) => {\n return this.modalService.dialog({\n title: _('catalog.remove-product-variant-from-channel'),\n buttons: [\n { type: 'secondary', label: _('common.cancel') },\n {\n type: 'danger',\n label: _('catalog.remove-from-channel'),\n translationVars: { channelCode },\n returnValue: true,\n },\n ],\n });\n }),\n switchMap(response =>\n response\n ? this.dataService.product.removeVariantsFromChannel({\n channelId,\n productVariantIds: [variant.id],\n })\n : EMPTY,\n ),\n )\n .subscribe(\n () => {\n this.notificationService.success(_('catalog.notify-remove-variant-from-channel-success'));\n },\n err => {\n this.notificationService.error(_('catalog.notify-remove-variant-from-channel-error'));\n },\n );\n }\n\n assetsChanged(): boolean {\n return !!Object.values(this.assetChanges).length;\n }\n\n variantAssetsChanged(): boolean {\n return !!Object.keys(this.variantAssetChanges).length;\n }\n\n variantAssetChange(event: VariantAssetChange) {\n this.variantAssetChanges[event.variantId] = event;\n }\n\n /**\n * If creating a new product, automatically generate the slug based on the product name.\n */\n updateSlug(nameValue: string) {\n combineLatest(this.entity$, this.languageCode$)\n .pipe(take(1))\n .subscribe(([entity, languageCode]) => {\n const slugControl = this.detailForm.get(['product', 'slug']);\n const currentTranslation = findTranslation(entity, languageCode);\n const currentSlugIsEmpty = !currentTranslation || !currentTranslation.slug;\n if (slugControl && slugControl.pristine && currentSlugIsEmpty) {\n slugControl.setValue(normalizeString(`${nameValue}`, '-'));\n }\n });\n }\n\n selectProductFacetValue() {\n this.displayFacetValueModal().subscribe(facetValueIds => {\n if (facetValueIds) {\n const productGroup = this.getProductFormGroup();\n const currentFacetValueIds = productGroup.value.facetValueIds;\n productGroup.patchValue({\n facetValueIds: unique([...currentFacetValueIds, ...facetValueIds]),\n });\n productGroup.markAsDirty();\n }\n });\n }\n\n updateProductOption(input: UpdateProductOptionInput & { autoUpdate: boolean }) {\n combineLatest(this.product$, this.languageCode$)\n .pipe(\n take(1),\n mergeMap(([product, languageCode]) =>\n this.productDetailService.updateProductOption(input, product, languageCode),\n ),\n )\n .subscribe(\n () => {\n this.notificationService.success(_('common.notify-update-success'), {\n entity: 'ProductOption',\n });\n },\n err => {\n this.notificationService.error(_('common.notify-update-error'), {\n entity: 'ProductOption',\n });\n },\n );\n }\n\n removeProductFacetValue(facetValueId: string) {\n const productGroup = this.getProductFormGroup();\n const currentFacetValueIds = productGroup.value.facetValueIds;\n productGroup.patchValue({\n facetValueIds: currentFacetValueIds.filter(id => id !== facetValueId),\n });\n productGroup.markAsDirty();\n }\n\n variantsToCreateAreValid(): boolean {\n return (\n 0 < this.createVariantsConfig.variants.length &&\n this.createVariantsConfig.variants.every(v => {\n return v.sku !== '';\n })\n );\n }\n\n private displayFacetValueModal(): Observable<string[] | undefined> {\n return this.modalService\n .fromComponent(ApplyFacetDialogComponent, {\n size: 'md',\n closable: true,\n })\n .pipe(map(facetValues => facetValues && facetValues.map(v => v.id)));\n }\n\n create() {\n const productGroup = this.getProductFormGroup();\n if (!productGroup.dirty) {\n return;\n }\n combineLatest(this.product$, this.languageCode$)\n .pipe(\n take(1),\n mergeMap(([product, languageCode]) => {\n const newProduct = this.getUpdatedProduct(\n product,\n productGroup as FormGroup,\n languageCode,\n ) as CreateProductInput;\n return this.productDetailService.createProductWithVariants(\n newProduct,\n this.createVariantsConfig,\n languageCode,\n );\n }),\n )\n .subscribe(\n ({ createProductVariants, productId }) => {\n this.notificationService.success(_('common.notify-create-success'), {\n entity: 'Product',\n });\n this.assetChanges = {};\n this.variantAssetChanges = {};\n this.detailForm.markAsPristine();\n this.router.navigate(['../', productId], { relativeTo: this.route });\n },\n err => {\n // tslint:disable-next-line:no-console\n console.error(err);\n this.notificationService.error(_('common.notify-create-error'), {\n entity: 'Product',\n });\n },\n );\n }\n\n save() {\n combineLatest(this.product$, this.languageCode$, this.channelPriceIncludesTax$)\n .pipe(\n take(1),\n mergeMap(([product, languageCode, priceIncludesTax]) => {\n const productGroup = this.getProductFormGroup();\n let productInput: UpdateProductInput | undefined;\n let variantsInput: UpdateProductVariantInput[] | undefined;\n\n if (productGroup.dirty || this.assetsChanged()) {\n productInput = this.getUpdatedProduct(\n product,\n productGroup as FormGroup,\n languageCode,\n ) as UpdateProductInput;\n }\n const variantsArray = this.detailForm.get('variants');\n if ((variantsArray && variantsArray.dirty) || this.variantAssetsChanged()) {\n variantsInput = this.getUpdatedProductVariants(\n product,\n variantsArray as FormArray,\n languageCode,\n priceIncludesTax,\n );\n }\n\n return this.productDetailService.updateProduct({\n product,\n languageCode,\n autoUpdate:\n this.detailForm.get(['product', 'autoUpdateVariantNames'])?.value ?? false,\n productInput,\n variantsInput,\n });\n }),\n )\n .subscribe(\n result => {\n this.updateSlugAfterSave(result);\n this.detailForm.markAsPristine();\n this.assetChanges = {};\n this.variantAssetChanges = {};\n this.variantFacetValueChanges = {};\n this.notificationService.success(_('common.notify-update-success'), {\n entity: 'Product',\n });\n this.changeDetector.markForCheck();\n },\n err => {\n this.notificationService.error(_('common.notify-update-error'), {\n entity: 'Product',\n });\n },\n );\n }\n\n canDeactivate(): boolean {\n return super.canDeactivate() && !this.assetChanges.assets && !this.assetChanges.featuredAsset;\n }\n\n /**\n * Sets the values of the form on changes to the product or current language.\n */\n protected setFormValues(\n product: NonNullable<GetProductWithVariantsQuery['product']>,\n languageCode: LanguageCode,\n ) {\n const currentTranslation = findTranslation(product, languageCode);\n this.detailForm.patchValue({\n product: {\n enabled: product.enabled,\n name: currentTranslation ? currentTranslation.name : '',\n slug: currentTranslation ? currentTranslation.slug : '',\n description: currentTranslation ? currentTranslation.description : '',\n facetValueIds: product.facetValues.map(fv => fv.id),\n },\n });\n\n if (this.customFields.length) {\n this.setCustomFieldFormValues(\n this.customFields,\n this.detailForm.get(['product', 'customFields']),\n product,\n currentTranslation,\n );\n }\n this.buildVariantFormArray(product.variantList.items, languageCode);\n }\n\n private buildVariantFormArray(variants: ProductVariantFragment[], languageCode: LanguageCode) {\n const variantsFormArray = this.detailForm.get('variants') as FormArray;\n variants.forEach((variant, i) => {\n const variantTranslation = findTranslation(variant, languageCode);\n const pendingFacetValueChanges = this.variantFacetValueChanges[variant.id];\n const facetValueIds = pendingFacetValueChanges\n ? pendingFacetValueChanges.map(fv => fv.id)\n : variant.facetValues.map(fv => fv.id);\n const group: VariantFormValue = {\n id: variant.id,\n enabled: variant.enabled,\n sku: variant.sku,\n name: variantTranslation ? variantTranslation.name : '',\n price: variant.price,\n priceWithTax: variant.priceWithTax,\n taxCategoryId: variant.taxCategory.id,\n stockOnHand: variant.stockOnHand,\n useGlobalOutOfStockThreshold: variant.useGlobalOutOfStockThreshold,\n outOfStockThreshold: variant.outOfStockThreshold,\n trackInventory: variant.trackInventory,\n facetValueIds,\n };\n\n let variantFormGroup = variantsFormArray.controls.find(c => c.value.id === variant.id) as\n | FormGroup\n | undefined;\n if (variantFormGroup) {\n if (variantFormGroup.pristine) {\n variantFormGroup.patchValue(group);\n }\n } else {\n variantFormGroup = this.formBuilder.group({\n ...group,\n facetValueIds: this.formBuilder.control(facetValueIds),\n });\n variantsFormArray.insert(i, variantFormGroup);\n }\n if (this.customVariantFields.length) {\n let customFieldsGroup = variantFormGroup.get(['customFields']) as FormGroup | undefined;\n\n if (!customFieldsGroup) {\n customFieldsGroup = this.formBuilder.group(\n this.customVariantFields.reduce((hash, field) => ({ ...hash, [field.name]: '' }), {}),\n );\n variantFormGroup.addControl('customFields', customFieldsGroup);\n }\n this.setCustomFieldFormValues(\n this.customVariantFields,\n customFieldsGroup,\n variant,\n variantTranslation,\n );\n }\n });\n }\n\n /**\n * Given a product and the value of the detailForm, this method creates an updated copy of the product which\n * can then be persisted to the API.\n */\n private getUpdatedProduct(\n product: NonNullable<GetProductWithVariantsQuery['product']>,\n productFormGroup: FormGroup,\n languageCode: LanguageCode,\n ): UpdateProductInput | CreateProductInput {\n const updatedProduct = createUpdatedTranslatable({\n translatable: product,\n updatedFields: productFormGroup.value,\n customFieldConfig: this.customFields,\n languageCode,\n defaultTranslation: {\n languageCode,\n name: product.name || '',\n slug: product.slug || '',\n description: product.description || '',\n },\n });\n return {\n ...updatedProduct,\n assetIds: this.assetChanges.assets?.map(a => a.id),\n featuredAssetId: this.assetChanges.featuredAsset?.id,\n facetValueIds: productFormGroup.value.facetValueIds,\n } as UpdateProductInput | CreateProductInput;\n }\n\n /**\n * Given an array of product variants and the values from the detailForm, this method creates an new array\n * which can be persisted to the API.\n */\n private getUpdatedProductVariants(\n product: NonNullable<GetProductWithVariantsQuery['product']>,\n variantsFormArray: FormArray,\n languageCode: LanguageCode,\n priceIncludesTax: boolean,\n ): UpdateProductVariantInput[] {\n const dirtyFormControls = variantsFormArray.controls.filter(c => c.dirty);\n const dirtyVariants = dirtyFormControls\n .map(c => this.productVariantMap.get(c.value.id))\n .filter(notNullOrUndefined);\n const dirtyVariantValues = dirtyFormControls.map(c => c.value);\n\n if (dirtyVariants.length !== dirtyVariantValues.length) {\n throw new Error(_(`error.product-variant-form-values-do-not-match`));\n }\n return dirtyVariants\n .map((variant, i) => {\n const formValue: VariantFormValue = dirtyVariantValues.find(value => value.id === variant.id);\n const result: UpdateProductVariantInput = createUpdatedTranslatable({\n translatable: variant,\n updatedFields: formValue,\n customFieldConfig: this.customVariantFields,\n languageCode,\n defaultTranslation: {\n languageCode,\n name: '',\n },\n });\n result.taxCategoryId = formValue.taxCategoryId;\n result.facetValueIds = formValue.facetValueIds;\n result.price = priceIncludesTax ? formValue.priceWithTax : formValue.price;\n const assetChanges = this.variantAssetChanges[variant.id];\n if (assetChanges) {\n result.featuredAssetId = assetChanges.featuredAsset?.id;\n result.assetIds = assetChanges.assets?.map(a => a.id);\n }\n return result;\n })\n .filter(notNullOrUndefined);\n }\n\n private getProductFormGroup(): FormGroup {\n return this.detailForm.get('product') as FormGroup;\n }\n\n /**\n * The server may alter the slug value in order to normalize and ensure uniqueness upon saving.\n */\n private updateSlugAfterSave(results: Array<UpdateProductMutation | UpdateProductVariantsMutation>) {\n const firstResult = results[0];\n const slugControl = this.detailForm.get(['product', 'slug']);\n\n function isUpdateMutation(input: any): input is UpdateProductMutation {\n return input.hasOwnProperty('updateProduct');\n }\n\n if (slugControl && isUpdateMutation(firstResult)) {\n slugControl.setValue(firstResult.updateProduct.slug, { emitEvent: false });\n }\n }\n}\n","<vdr-action-bar>\r\n <vdr-ab-left [grow]=\"true\">\r\n <div class=\"search-form\">\r\n <vdr-product-search-input\r\n #productSearchInputComponent\r\n [facetValueResults]=\"facetValues$ | async\"\r\n (searchTermChange)=\"setSearchTerm($event)\"\r\n (facetValueChange)=\"setFacetValueIds($event)\"\r\n ></vdr-product-search-input>\r\n <vdr-dropdown class=\"search-settings-menu mr3\">\r\n <button\r\n type=\"button\"\r\n class=\"icon-button search-index-button\"\r\n [title]=\"\r\n (pendingSearchIndexUpdates\r\n ? 'catalog.pending-search-index-updates'\r\n : 'catalog.search-index-controls'\r\n ) | translate\r\n \"\r\n vdrDropdownTrigger\r\n >\r\n <clr-icon shape=\"cog\"></clr-icon>\r\n <vdr-status-badge *ngIf=\"pendingSearchIndexUpdates\" type=\"warning\"></vdr-status-badge>\r\n </button>\r\n <vdr-dropdown-menu vdrPosition=\"bottom-right\">\r\n <h4 class=\"dropdown-header\">{{ 'catalog.search-index-controls' | translate }}</h4>\r\n <ng-container *ngIf=\"pendingSearchIndexUpdates\">\r\n <button\r\n type=\"button\"\r\n class=\"run-updates-button\"\r\n vdrDropdownItem\r\n (click)=\"runPendingSearchIndexUpdates()\"\r\n [disabled]=\"!(['UpdateCatalog', 'UpdateProduct'] | hasPermission)\"\r\n >\r\n <vdr-status-badge type=\"warning\"></vdr-status-badge>\r\n {{\r\n 'catalog.run-pending-search-index-updates'\r\n | translate: { count: pendingSearchIndexUpdates }\r\n }}\r\n </button>\r\n <div class=\"dropdown-divider\"></div>\r\n </ng-container>\r\n <button\r\n type=\"button\"\r\n vdrDropdownItem\r\n (click)=\"rebuildSearchIndex()\"\r\n [disabled]=\"!(['UpdateCatalog', 'UpdateProduct'] | hasPermission)\"\r\n >\r\n {{ 'catalog.rebuild-search-index' | translate }}\r\n </button>\r\n </vdr-dropdown-menu>\r\n </vdr-dropdown>\r\n </div>\r\n <div class=\"flex wrap\">\r\n <clr-toggle-wrapper class=\"mt2\">\r\n <input type=\"checkbox\" clrToggle [(ngModel)]=\"groupByProduct\" (ngModelChange)=\"refresh()\" />\r\n <label>\r\n {{ 'catalog.group-by-product' | translate }}\r\n </label>\r\n </clr-toggle-wrapper>\r\n <vdr-language-selector\r\n [availableLanguageCodes]=\"availableLanguages$ | async\"\r\n [currentLanguageCode]=\"contentLanguage$ | async\"\r\n (languageCodeChange)=\"setLanguage($event)\"\r\n ></vdr-language-selector>\r\n </div>\r\n </vdr-ab-left>\r\n <vdr-ab-right>\r\n <vdr-action-bar-items locationId=\"product-list\"></vdr-action-bar-items>\r\n <a\r\n class=\"btn btn-primary\"\r\n [routerLink]=\"['./create']\"\r\n *vdrIfPermissions=\"['CreateCatalog', 'CreateProduct']\"\r\n >\r\n <clr-icon shape=\"plus\"></clr-icon>\r\n {{ 'catalog.create-new-product' | translate }}\r\n </a>\r\n </vdr-ab-right>\r\n</vdr-action-bar>\r\n\r\n<vdr-data-table\r\n [items]=\"items$ | async\"\r\n [itemsPerPage]=\"itemsPerPage$ | async\"\r\n [totalItems]=\"totalItems$ | async\"\r\n [currentPage]=\"currentPage$ | async\"\r\n (pageChange)=\"setPageNumber($event)\"\r\n (itemsPerPageChange)=\"setItemsPerPage($event)\"\r\n [selectionManager]=\"selectionManager\"\r\n>\r\n <vdr-bulk-action-menu\r\n locationId=\"product-list\"\r\n [hostComponent]=\"this\"\r\n [selectionManager]=\"selectionManager\"\r\n ></vdr-bulk-action-menu>\r\n <vdr-dt-column> </vdr-dt-column>\r\n <vdr-dt-column></vdr-dt-column>\r\n <vdr-dt-column></vdr-dt-column>\r\n <vdr-dt-column></vdr-dt-column>\r\n <ng-template let-result=\"item\">\r\n <td class=\"left align-middle image-col\" [class.disabled]=\"!result.enabled\">\r\n <div class=\"image-placeholder\">\r\n <img\r\n *ngIf=\"\r\n groupByProduct\r\n ? result.productAsset\r\n : result.productVariantAsset || result.productAsset as asset;\r\n else imagePlaceholder\r\n \"\r\n [src]=\"asset | assetPreview: 'tiny'\"\r\n />\r\n <ng-template #imagePlaceholder>\r\n <div class=\"placeholder\">\r\n <clr-icon shape=\"image\" size=\"48\"></clr-icon>\r\n </div>\r\n </ng-template>\r\n </div>\r\n </td>\r\n <td class=\"left align-middle\" [class.disabled]=\"!result.enabled\">\r\n <div>{{ groupByProduct ? result.productName : result.productVariantName }}</div>\r\n <div *ngIf=\"!groupByProduct\" class=\"sku\">{{ result.sku }}</div>\r\n </td>\r\n <td class=\"align-middle\" [class.disabled]=\"!result.enabled\">\r\n <vdr-chip *ngIf=\"!result.enabled\">{{ 'common.disabled' | translate }}</vdr-chip>\r\n </td>\r\n <td class=\"right align-middle\" [class.disabled]=\"!result.enabled\">\r\n <vdr-table-row-action\r\n class=\"edit-button\"\r\n iconShape=\"edit\"\r\n [label]=\"'common.edit' | translate\"\r\n [linkTo]=\"['./', result.productId]\"\r\n ></vdr-table-row-action>\r\n <vdr-dropdown>\r\n <button type=\"button\" class=\"btn btn-link btn-sm\" vdrDropdownTrigger>\r\n {{ 'common.actions' | translate }}\r\n <clr-icon shape=\"caret down\"></clr-icon>\r\n </button>\r\n <vdr-dropdown-menu vdrPosition=\"bottom-right\">\r\n <button\r\n type=\"button\"\r\n class=\"delete-button\"\r\n (click)=\"deleteProduct(result.productId)\"\r\n [disabled]=\"!(['DeleteCatalog', 'DeleteProduct'] | hasPermission)\"\r\n vdrDropdownItem\r\n >\r\n <clr-icon shape=\"trash\" class=\"is-danger\"></clr-icon>\r\n {{ 'common.delete' | translate }}\r\n </button>\r\n </vdr-dropdown-menu>\r\n </vdr-dropdown>\r\n </td>\r\n </ng-template>\r\n</vdr-data-table>\r\n","import { AfterViewInit, Component, OnInit, ViewChild } from '@angular/core';\r\nimport { ActivatedRoute, Router } from '@angular/router';\r\nimport { marker as _ } from '@biesbjerg/ngx-translate-extract-marker';\r\nimport {\r\n BaseListComponent,\r\n DataService,\r\n ItemOf,\r\n JobQueueService,\r\n JobState,\r\n LanguageCode,\r\n LogicalOperator,\r\n ModalService,\r\n NotificationService,\r\n ProductSearchInputComponent,\r\n SearchInput,\r\n SearchProductsQuery,\r\n SearchProductsQueryVariables,\r\n SelectionManager,\r\n ServerConfigService,\r\n} from '@vendure/admin-ui/core';\r\nimport { EMPTY, Observable } from 'rxjs';\r\nimport { delay, map, switchMap, take, takeUntil, tap, withLatestFrom } from 'rxjs/operators';\r\n\r\nexport type SearchItem = ItemOf<SearchProductsQuery, 'search'>;\r\n\r\n@Component({\r\n selector: 'vdr-products-list',\r\n templateUrl: './product-list.component.html',\r\n styleUrls: ['./product-list.component.scss'],\r\n})\r\nexport class ProductListComponent\r\n extends BaseListComponent<\r\n SearchProductsQuery,\r\n SearchItem,\r\n SearchProductsQueryVariables\r\n >\r\n implements OnInit, AfterViewInit\r\n{\r\n searchTerm = '';\r\n facetValueIds: string[] = [];\r\n groupByProduct = true;\r\n selectedFacetValueIds$: Observable<string[]>;\r\n facetValues$: Observable<SearchProductsQuery['search']['facetValues']>;\r\n availableLanguages$: Observable<LanguageCode[]>;\r\n contentLanguage$: Observable<LanguageCode>;\r\n pendingSearchIndexUpdates = 0;\r\n selectionManager: SelectionManager<SearchItem>;\r\n\r\n @ViewChild('productSearchInputComponent', { static: true })\r\n private productSearchInput: ProductSearchInputComponent;\r\n\r\n constructor(\r\n private dataService: DataService,\r\n private modalService: ModalService,\r\n private notificationService: NotificationService,\r\n private jobQueueService: JobQueueService,\r\n private serverConfigService: ServerConfigService,\r\n router: Router,\r\n route: ActivatedRoute,\r\n ) {\r\n super(router, route);\r\n this.route.queryParamMap\r\n .pipe(\r\n map(qpm => qpm.get('q')),\r\n takeUntil(this.destroy$),\r\n )\r\n .subscribe(term => {\r\n this.searchTerm = term || '';\r\n if (this.productSearchInput) {\r\n this.productSearchInput.setSearchTerm(term);\r\n }\r\n });\r\n this.selectedFacetValueIds$ = this.route.queryParamMap.pipe(map(qpm => qpm.getAll('fvids')));\r\n\r\n this.selectedFacetValueIds$.pipe(takeUntil(this.destroy$)).subscribe(ids => {\r\n this.facetValueIds = ids;\r\n if (this.productSearchInput) {\r\n this.productSearchInput.setFacetValues(ids);\r\n }\r\n });\r\n super.setQueryFn(\r\n (...args: any[]) =>\r\n this.dataService.product.searchProducts(this.searchTerm, ...args).refetchOnChannelChange(),\r\n data => data.search,\r\n // tslint:disable-next-line:no-shadowed-variable\r\n (skip, take) => ({\r\n input: {\r\n skip,\r\n take,\r\n term: this.searchTerm,\r\n facetValueIds: this.facetValueIds,\r\n facetValueOperator: LogicalOperator.AND,\r\n groupByProduct: this.groupByProduct,\r\n } as SearchInput,\r\n }),\r\n );\r\n this.selectionManager = new SelectionManager({\r\n multiSelect: true,\r\n itemsAreEqual: (a, b) =>\r\n this.groupByProduct ? a.productId === b.productId : a.productVariantId === b.productVariantId,\r\n additiveMode: true,\r\n });\r\n }\r\n\r\n ngOnInit() {\r\n super.ngOnInit();\r\n\r\n this.facetValues$ = this.result$.pipe(map(data => data.search.facetValues));\r\n\r\n this.facetValues$\r\n .pipe(take(1), delay(100), withLatestFrom(this.selectedFacetValueIds$))\r\n .subscribe(([__, ids]) => {\r\n this.productSearchInput.setFacetValues(ids);\r\n });\r\n this.availableLanguages$ = this.serverConfigService.getAvailableLanguages();\r\n this.contentLanguage$ = this.dataService.client\r\n .uiState()\r\n .mapStream(({ uiState }) => uiState.contentLanguage)\r\n .pipe(tap(() => this.refresh()));\r\n\r\n this.dataService.product\r\n .getPendingSearchIndexUpdates()\r\n .mapSingle(({ pendingSearchIndexUpdates }) => pendingSearchIndexUpdates)\r\n .subscribe(value => (this.pendingSearchIndexUpdates = value));\r\n }\r\n\r\n ngAfterViewInit() {\r\n if (this.productSearchInput && this.searchTerm) {\r\n setTimeout(() => this.productSearchInput.setSearchTerm(this.searchTerm));\r\n }\r\n }\r\n\r\n setSearchTerm(term: string) {\r\n this.searchTerm = term;\r\n this.setQueryParam({ q: term || null, page: 1 });\r\n this.refresh();\r\n }\r\n\r\n setFacetValueIds(ids: string[]) {\r\n this.facetValueIds = ids;\r\n this.setQueryParam({ fvids: ids, page: 1 });\r\n this.refresh();\r\n }\r\n\r\n rebuildSearchIndex() {\r\n this.dataService.product.reindex().subscribe(({ reindex }) => {\r\n this.notificationService.info(_('catalog.reindexing'));\r\n this.jobQueueService.addJob(reindex.id, job => {\r\n if (job.state === JobState.COMPLETED) {\r\n const time = new Intl.NumberFormat().format(job.duration || 0);\r\n this.notificationService.success(_('catalog.reindex-successful'), {\r\n count: job.result.indexedItemCount,\r\n time,\r\n });\r\n this.refresh();\r\n } else {\r\n this.notificationService.error(_('catalog.reindex-error'));\r\n }\r\n });\r\n });\r\n }\r\n\r\n runPendingSearchIndexUpdates() {\r\n this.dataService.product.runPendingSearchIndexUpdates().subscribe(value => {\r\n this.notificationService.info(_('catalog.running-search-index-updates'), {\r\n count: this.pendingSearchIndexUpdates,\r\n });\r\n this.pendingSearchIndexUpdates = 0;\r\n });\r\n }\r\n\r\n deleteProduct(productId: string) {\r\n this.modalService\r\n .dialog({\r\n title: _('catalog.confirm-delete-product'),\r\n buttons: [\r\n { type: 'secondary', label: _('common.cancel') },\r\n { type: 'danger', label: _('common.delete'), returnValue: true },\r\n ],\r\n })\r\n .pipe(\r\n switchMap(response => (response ? this.dataService.product.deleteProduct(productId) : EMPTY)),\r\n // Short delay to allow the product to be removed from the search index before\r\n // refreshing.\r\n delay(500),\r\n )\r\n .subscribe(\r\n () => {\r\n this.notificationService.success(_('common.notify-delete-success'), {\r\n entity: 'Product',\r\n });\r\n this.refresh();\r\n },\r\n err => {\r\n this.notificationService.error(_('common.notify-delete-error'), {\r\n entity: 'Product',\r\n });\r\n },\r\n );\r\n }\r\n\r\n setLanguage(code: LanguageCode) {\r\n this.dataService.client.setContentLanguage(code).subscribe();\r\n }\r\n}\r\n","<vdr-action-bar>\r\n <vdr-ab-left>\r\n <vdr-language-selector\r\n [availableLanguageCodes]=\"availableLanguages$ | async\"\r\n [currentLanguageCode]=\"languageCode$ | async\"\r\n (languageCodeChange)=\"setLanguage($event)\"\r\n ></vdr-language-selector>\r\n </vdr-ab-left>\r\n\r\n <vdr-ab-right>\r\n <div class=\"flex center\">\r\n <div class=\"mr2\">\r\n <clr-checkbox-wrapper>\r\n <input\r\n clrCheckbox\r\n type=\"checkbox\"\r\n id=\"auto-update\"\r\n [(ngModel)]=\"autoUpdateVariantNames\"\r\n />\r\n <label>{{ 'catalog.auto-update-product-variant-name' | translate }}</label>\r\n </clr-checkbox-wrapper>\r\n </div>\r\n <button\r\n *vdrIfPermissions=\"updatePermission\"\r\n class=\"btn btn-primary\"\r\n (click)=\"save()\"\r\n [disabled]=\"detailForm.pristine || detailForm.invalid\"\r\n >\r\n {{ 'common.update' | translate }}\r\n </button>\r\n </div>\r\n </vdr-ab-right>\r\n</vdr-action-bar>\r\n<form class=\"form\" [formGroup]=\"detailForm\" *ngIf=\"optionGroups$ | async as optionGroups\">\r\n <div formGroupName=\"optionGroups\" class=\"clr-row\">\r\n <div class=\"clr-col-12 clr-col-xl-6\" *ngFor=\"let optionGroup of getOptionGroups(); index as i\">\r\n <section class=\"card\" [formArrayName]=\"i\">\r\n <div class=\"card-header option-group-header\">\r\n <vdr-entity-info [entity]=\"optionGroup.value\"></vdr-entity-info>\r\n <div class=\"ml2\">{{ optionGroup.value.code }}</div>\r\n </div>\r\n <div class=\"card-block\">\r\n <vdr-form-field [label]=\"'common.name' | translate\" for=\"name\">\r\n <input\r\n [id]=\"'name-' + i\"\r\n type=\"text\"\r\n formControlName=\"name\"\r\n [readonly]=\"!(updatePermission | hasPermission)\"\r\n />\r\n </vdr-form-field>\r\n <vdr-form-field [label]=\"'common.code' | translate\" for=\"code\">\r\n <input\r\n [id]=\"'code-' + i\"\r\n type=\"text\"\r\n [readonly]=\"!(updatePermission | hasPermission)\"\r\n formControlName=\"code\"\r\n />\r\n </vdr-form-field>\r\n </div>\r\n <section class=\"card-block\">\r\n <table class=\"facet-values-list table mt2 mb4\" formGroupName=\"options\">\r\n <thead>\r\n <tr>\r\n <th></th>\r\n <th>{{ 'common.name' | translate }}</th>\r\n <th>{{ 'common.code' | translate }}</th>\r\n </tr>\r\n </thead>\r\n <tbody>\r\n <tr\r\n class=\"facet-value\"\r\n *ngFor=\"let option of getOptions(optionGroup); let i = index\"\r\n [formGroupName]=\"i\"\r\n >\r\n <td class=\"align-middle\">\r\n <vdr-entity-info [entity]=\"option.value\"></vdr-entity-info>\r\n </td>\r\n <td class=\"align-middle\">\r\n <input\r\n type=\"text\"\r\n formControlName=\"name\"\r\n [readonly]=\"!(updatePermission | hasPermission)\"\r\n />\r\n </td>\r\n <td class=\"align-middle\"><input type=\"text\" formControlName=\"code\" /></td>\r\n </tr>\r\n </tbody>\r\n </table>\r\n </section>\r\n </section>\r\n </div>\r\n </div>\r\n</form>\r\n","import { ChangeDetectionStrategy, ChangeDetectorRef, Component, OnInit } from '@angular/core';\r\nimport { FormArray, FormBuilder, FormGroup } from '@angular/forms';\r\nimport { ActivatedRoute, Router } from '@angular/router';\r\nimport { marker as _ } from '@biesbjerg/ngx-translate-extract-marker';\r\nimport {\r\n BaseDetailComponent,\r\n createUpdatedTranslatable,\r\n CustomFieldConfig,\r\n DataService,\r\n findTranslation,\r\n GetProductVariantOptionsQuery,\r\n LanguageCode,\r\n NotificationService,\r\n Permission,\r\n ProductOptionFragment,\r\n ProductOptionGroup,\r\n ProductOptionGroupFragment,\r\n ServerConfigService,\r\n UpdateProductOptionGroupInput,\r\n UpdateProductOptionInput,\r\n} from '@vendure/admin-ui/core';\r\nimport { combineLatest, forkJoin, Observable } from 'rxjs';\r\nimport { map, mergeMap, take } from 'rxjs/operators';\r\n\r\nimport { ProductDetailService } from '../../providers/product-detail/product-detail.service';\r\n\r\ntype ProductWithOptions = NonNullable<GetProductVariantOptionsQuery['product']>;\r\n\r\n@Component({\r\n selector: 'vdr-product-options-editor',\r\n templateUrl: './product-options-editor.component.html',\r\n styleUrls: ['./product-options-editor.component.scss'],\r\n changeDetection: ChangeDetectionStrategy.OnPush,\r\n})\r\nexport class ProductOptionsEditorComponent extends BaseDetailComponent<ProductWithOptions> implements OnInit {\r\n detailForm: FormGroup;\r\n optionGroups$: Observable<ProductWithOptions['optionGroups']>;\r\n languageCode$: Observable<LanguageCode>;\r\n availableLanguages$: Observable<LanguageCode[]>;\r\n optionGroupCustomFields: CustomFieldConfig[];\r\n optionCustomFields: CustomFieldConfig[];\r\n autoUpdateVariantNames = true;\r\n readonly updatePermission = [Permission.UpdateCatalog, Permission.UpdateProduct];\r\n\r\n constructor(\r\n protected route: ActivatedRoute,\r\n protected router: Router,\r\n protected serverConfigService: ServerConfigService,\r\n protected dataService: DataService,\r\n private productDetailService: ProductDetailService,\r\n private formBuilder: FormBuilder,\r\n private changeDetector: ChangeDetectorRef,\r\n private notificationService: NotificationService,\r\n ) {\r\n super(route, router, serverConfigService, dataService);\r\n this.optionGroupCustomFields = this.getCustomFieldConfig('ProductOptionGroup');\r\n this.optionCustomFields = this.getCustomFieldConfig('ProductOption');\r\n }\r\n\r\n ngOnInit(): void {\r\n this.optionGroups$ = this.route.snapshot.data.entity.pipe(\r\n map((product: ProductWithOptions) => product.optionGroups),\r\n );\r\n this.detailForm = new FormGroup({\r\n optionGroups: new FormArray([]),\r\n });\r\n super.init();\r\n }\r\n\r\n getOptionGroups(): FormGroup[] {\r\n const optionGroups = this.detailForm.get('optionGroups');\r\n return (optionGroups as FormArray).controls as FormGroup[];\r\n }\r\n\r\n getOptions(optionGroup: FormGroup): FormGroup[] {\r\n const options = optionGroup.get('options');\r\n return (options as FormArray).controls as FormGroup[];\r\n }\r\n\r\n save() {\r\n if (this.detailForm.invalid || this.detailForm.pristine) {\r\n return;\r\n }\r\n // tslint:disable-next-line:no-non-null-assertion\r\n const $product = this.dataService.product.getProduct(this.id).mapSingle(data => data.product!);\r\n combineLatest(this.entity$, this.languageCode$, $product)\r\n .pipe(\r\n take(1),\r\n mergeMap(([{ optionGroups }, languageCode, product]) => {\r\n const updateOperations: Array<Observable<any>> = [];\r\n for (const optionGroupForm of this.getOptionGroups()) {\r\n if (optionGroupForm.get('name')?.dirty || optionGroupForm.get('code')?.dirty) {\r\n const optionGroupEntity = optionGroups.find(\r\n og => og.id === optionGroupForm.value.id,\r\n );\r\n if (optionGroupEntity) {\r\n const input = this.getUpdatedOptionGroup(\r\n optionGroupEntity,\r\n optionGroupForm,\r\n languageCode,\r\n );\r\n updateOperations.push(\r\n this.dataService.product.updateProductOptionGroup(input),\r\n );\r\n }\r\n }\r\n\r\n for (const optionForm of this.getOptions(optionGroupForm)) {\r\n if (optionForm.get('name')?.dirty || optionForm.get('code')?.dirty) {\r\n const optionGroup = optionGroups\r\n .find(og => og.id === optionGroupForm.value.id)\r\n ?.options.find(o => o.id === optionForm.value.id);\r\n if (optionGroup) {\r\n const input = this.getUpdatedOption(\r\n optionGroup,\r\n optionForm,\r\n languageCode,\r\n );\r\n updateOperations.push(\r\n this.productDetailService.updateProductOption(\r\n { ...input, autoUpdate: this.autoUpdateVariantNames },\r\n product,\r\n languageCode,\r\n ),\r\n );\r\n }\r\n }\r\n }\r\n }\r\n return forkJoin(updateOperations);\r\n }),\r\n )\r\n .subscribe(\r\n () => {\r\n this.detailForm.markAsPristine();\r\n this.changeDetector.markForCheck();\r\n this.notificationService.success(_('common.notify-update-success'), {\r\n entity: 'ProductOptionGroup',\r\n });\r\n },\r\n err => {\r\n this.notificationService.error(_('common.notify-update-error'), {\r\n entity: 'ProductOptionGroup',\r\n });\r\n },\r\n );\r\n }\r\n\r\n private getUpdatedOptionGroup(\r\n optionGroup: ProductOptionGroupFragment,\r\n optionGroupFormGroup: FormGroup,\r\n languageCode: LanguageCode,\r\n ): UpdateProductOptionGroupInput {\r\n const input = createUpdatedTranslatable({\r\n translatable: optionGroup,\r\n updatedFields: optionGroupFormGroup.value,\r\n customFieldConfig: this.optionGroupCustomFields,\r\n languageCode,\r\n defaultTranslation: {\r\n languageCode,\r\n name: optionGroup.name || '',\r\n },\r\n });\r\n return input;\r\n }\r\n\r\n private getUpdatedOption(\r\n option: ProductOptionFragment,\r\n optionFormGroup: FormGroup,\r\n languageCode: LanguageCode,\r\n ): UpdateProductOptionInput {\r\n const input = createUpdatedTranslatable({\r\n translatable: option,\r\n updatedFields: optionFormGroup.value,\r\n customFieldConfig: this.optionGroupCustomFields,\r\n languageCode,\r\n defaultTranslation: {\r\n languageCode,\r\n name: option.name || '',\r\n },\r\n });\r\n return input;\r\n }\r\n\r\n protected setFormValues(entity: ProductWithOptions, languageCode: LanguageCode): void {\r\n const groupsFormArray = new FormArray([]);\r\n for (const optionGroup of entity.optionGroups) {\r\n const groupTranslation = findTranslation(optionGroup, languageCode);\r\n const group = {\r\n id: optionGroup.id,\r\n createdAt: optionGroup.createdAt,\r\n updatedAt: optionGroup.updatedAt,\r\n code: optionGroup.code,\r\n name: groupTranslation ? groupTranslation.name : '',\r\n };\r\n const optionsFormArray = new FormArray([]);\r\n\r\n for (const option of optionGroup.options) {\r\n const optionTranslation = findTranslation(option, languageCode);\r\n const optionControl = this.formBuilder.group({\r\n id: option.id,\r\n createdAt: option.createdAt,\r\n updatedAt: option.updatedAt,\r\n code: option.code,\r\n name: optionTranslation ? optionTranslation.name : '',\r\n });\r\n optionsFormArray.push(optionControl);\r\n }\r\n\r\n const groupControl = this.formBuilder.group(group);\r\n groupControl.addControl('options', optionsFormArray);\r\n groupsFormArray.push(groupControl);\r\n }\r\n this.detailForm.setControl('optionGroups', groupsFormArray);\r\n }\r\n}\r\n","<ng-template vdrDialogTitle>\r\n {{ 'catalog.confirm-deletion-of-unused-variants-title' | translate }}\r\n</ng-template>\r\n{{ 'catalog.confirm-deletion-of-unused-variants-body' | translate }}\r\n<ul>\r\n <li *ngFor=\"let variant of variants\">{{ variant.name }} ({{ variant.sku }})</li>\r\n</ul>\r\n<ng-template vdrDialogButtons>\r\n <button type=\"button\" class=\"btn\" (click)=\"cancel()\">{{ 'common.cancel' | translate }}</button>\r\n <button type=\"submit\" (click)=\"confirm()\" class=\"btn btn-primary\">\r\n {{ 'common.confirm' | translate }}\r\n </button>\r\n</ng-template>\r\n","import { ChangeDetectionStrategy, Component } from '@angular/core';\r\nimport { Dialog, GetProductVariantOptionsQuery } from '@vendure/admin-ui/core';\r\n\r\n@Component({\r\n selector: 'vdr-confirm-variant-deletion-dialog',\r\n templateUrl: './confirm-variant-deletion-dialog.component.html',\r\n styleUrls: ['./confirm-variant-deletion-dialog.component.scss'],\r\n changeDetection: ChangeDetectionStrategy.OnPush,\r\n})\r\nexport class ConfirmVariantDeletionDialogComponent implements Dialog<boolean> {\r\n resolveWith: (result?: boolean) => void;\r\n variants: NonNullable<GetProductVariantOptionsQuery['product']>['variants'] = [];\r\n\r\n confirm() {\r\n this.resolveWith(true);\r\n }\r\n\r\n cancel() {\r\n this.resolveWith();\r\n }\r\n}\r\n","<vdr-action-bar>\r\n <vdr-ab-right>\r\n <button\r\n class=\"btn btn-primary\"\r\n (click)=\"save()\"\r\n [disabled]=\"(!formValueChanged && !optionsChanged) || getVariantsToAdd().length === 0\"\r\n >\r\n {{ 'common.add-new-variants' | translate: { count: getVariantsToAdd().length } }}\r\n </button>\r\n </vdr-ab-right>\r\n</vdr-action-bar>\r\n\r\n<div *ngFor=\"let group of optionGroups; index as i\" class=\"option-groups\">\r\n <div class=\"name\">\r\n <label>{{ 'catalog.option' | translate }}</label>\r\n <input clrInput [(ngModel)]=\"group.name\" name=\"name\" [readonly]=\"!group.isNew\" />\r\n </div>\r\n <div class=\"values\">\r\n <label>{{ 'catalog.option-values' | translate }}</label>\r\n <vdr-option-value-input\r\n #optionValueInputComponent\r\n [options]=\"group.values\"\r\n [groupName]=\"group.name\"\r\n [disabled]=\"group.name === ''\"\r\n (add)=\"addOption(i, $event.name)\"\r\n (remove)=\"removeOption(i, $event)\"\r\n ></vdr-option-value-input>\r\n </div>\r\n <div>\r\n <button\r\n [disabled]=\"group.locked\"\r\n class=\"btn btn-icon btn-danger-outline mt5\" (click)=\"removeOptionGroup(group)\">\r\n <clr-icon shape=\"trash\"></clr-icon>\r\n </button>\r\n </div>\r\n</div>\r\n<button class=\"btn btn-primary-outline btn-sm\" (click)=\"addOptionGroup()\">\r\n <clr-icon shape=\"plus\"></clr-icon>\r\n {{ 'catalog.add-option' | translate }}\r\n</button>\r\n\r\n<div class=\"variants-preview\">\r\n <table class=\"table\">\r\n <thead>\r\n <tr>\r\n <th></th>\r\n <th>{{ 'catalog.variant' | translate }}</th>\r\n <th>{{ 'catalog.sku' | translate }}</th>\r\n <th>{{ 'catalog.price' | translate }}</th>\r\n <th>{{ 'catalog.stock-on-hand' | translate }}</th>\r\n <th></th>\r\n </tr>\r\n </thead>\r\n <tr *ngFor=\"let variant of generatedVariants\" [class.disabled]=\"!variant.enabled || variant.existing\">\r\n <td class=\"left\">\r\n <clr-checkbox-wrapper *ngIf=\"!variant.existing\">\r\n <input\r\n type=\"checkbox\"\r\n [(ngModel)]=\"variant.enabled\"\r\n name=\"enabled\"\r\n clrCheckbox\r\n (ngModelChange)=\"formValueChanged = true\"\r\n />\r\n <label>{{ 'common.create' | translate }}</label>\r\n </clr-checkbox-wrapper>\r\n </td>\r\n <td>\r\n {{ getVariantName(variant) | translate }}\r\n </td>\r\n <td>\r\n <div class=\"flex center\">\r\n <clr-input-container *ngIf=\"!variant.existing\">\r\n <input\r\n clrInput\r\n type=\"text\"\r\n [(ngModel)]=\"variant.sku\"\r\n [placeholder]=\"'catalog.sku' | translate\"\r\n name=\"sku\"\r\n required\r\n (ngModelChange)=\"onFormChanged(variant)\"\r\n />\r\n </clr-input-container>\r\n <span *ngIf=\"variant.existing\">{{ variant.sku }}</span>\r\n </div>\r\n </td>\r\n <td>\r\n <div class=\"flex center\">\r\n <clr-input-container *ngIf=\"!variant.existing\">\r\n <vdr-currency-input\r\n clrInput\r\n [(ngModel)]=\"variant.price\"\r\n name=\"price\"\r\n [currencyCode]=\"currencyCode\"\r\n (ngModelChange)=\"onFormChanged(variant)\"\r\n ></vdr-currency-input>\r\n </clr-input-container>\r\n <span *ngIf=\"variant.existing\">{{ variant.price | localeCurrency: currencyCode }}</span>\r\n </div>\r\n </td>\r\n <td>\r\n <div class=\"flex center\">\r\n <clr-input-container *ngIf=\"!variant.existing\">\r\n <input\r\n clrInput\r\n type=\"number\"\r\n [(ngModel)]=\"variant.stock\"\r\n name=\"stock\"\r\n min=\"0\"\r\n step=\"1\"\r\n (ngModelChange)=\"onFormChanged(variant)\"\r\n />\r\n </clr-input-container>\r\n <span *ngIf=\"variant.existing\">{{ variant.stock }}</span>\r\n </div>\r\n </td>\r\n <td>\r\n <vdr-dropdown *ngIf=\"variant.productVariantId as productVariantId\">\r\n <button class=\"icon-button\" vdrDropdownTrigger>\r\n <clr-icon shape=\"ellipsis-vertical\"></clr-icon>\r\n </button>\r\n <vdr-dropdown-menu vdrPosition=\"bottom-right\">\r\n <button\r\n type=\"button\"\r\n class=\"delete-button\"\r\n (click)=\"deleteVariant(productVariantId, variant.options)\"\r\n vdrDropdownItem\r\n >\r\n <clr-icon shape=\"trash\" class=\"is-danger\"></clr-icon>\r\n {{ 'common.delete' | translate }}\r\n </button>\r\n </vdr-dropdown-menu>\r\n </vdr-dropdown>\r\n </td>\r\n </tr>\r\n </table>\r\n</div>\r\n","import { ChangeDetectionStrategy, Component, OnInit } from '@angular/core';\r\nimport { ActivatedRoute } from '@angular/router';\r\nimport { marker as _ } from '@biesbjerg/ngx-translate-extract-marker';\r\nimport {\r\n CreateProductOptionGroupMutation,\r\n CreateProductOptionInput,\r\n CurrencyCode,\r\n DataService,\r\n DeactivateAware,\r\n DeletionResult,\r\n getDefaultUiLanguage,\r\n GetProductVariantOptionsQuery,\r\n LanguageCode,\r\n ModalService,\r\n NotificationService,\r\n ProductOptionGroupWithOptionsFragment,\r\n} from '@vendure/admin-ui/core';\r\nimport { normalizeString } from '@vendure/common/lib/normalize-string';\r\nimport { pick } from '@vendure/common/lib/pick';\r\nimport { generateAllCombinations, notNullOrUndefined } from '@vendure/common/lib/shared-utils';\r\nimport { unique } from '@vendure/common/lib/unique';\r\nimport { EMPTY, forkJoin, Observable, of } from 'rxjs';\r\nimport { defaultIfEmpty, filter, map, mergeMap, switchMap } from 'rxjs/operators';\r\n\r\nimport { ProductDetailService } from '../../providers/product-detail/product-detail.service';\r\nimport { ConfirmVariantDeletionDialogComponent } from '../confirm-variant-deletion-dialog/confirm-variant-deletion-dialog.component';\r\n\r\nexport class GeneratedVariant {\r\n isDefault: boolean;\r\n options: Array<{ name: string; id?: string }>;\r\n productVariantId?: string;\r\n enabled: boolean;\r\n existing: boolean;\r\n sku: string;\r\n price: number;\r\n stock: number;\r\n\r\n constructor(config: Partial<GeneratedVariant>) {\r\n for (const key of Object.keys(config)) {\r\n this[key] = config[key];\r\n }\r\n }\r\n}\r\n\r\ninterface OptionGroupUiModel {\r\n id?: string;\r\n isNew: boolean;\r\n name: string;\r\n locked: boolean;\r\n values: Array<{\r\n id?: string;\r\n name: string;\r\n locked: boolean;\r\n }>;\r\n}\r\n\r\n@Component({\r\n selector: 'vdr-product-variants-editor',\r\n templateUrl: './product-variants-editor.component.html',\r\n styleUrls: ['./product-variants-editor.component.scss'],\r\n changeDetection: ChangeDetectionStrategy.Default,\r\n})\r\nexport class ProductVariantsEditorComponent implements OnInit, DeactivateAware {\r\n formValueChanged = false;\r\n optionsChanged = false;\r\n generatedVariants: GeneratedVariant[] = [];\r\n optionGroups: OptionGroupUiModel[];\r\n product: NonNullable<GetProductVariantOptionsQuery['product']>;\r\n currencyCode: CurrencyCode;\r\n private languageCode: LanguageCode;\r\n\r\n constructor(\r\n private route: ActivatedRoute,\r\n private dataService: DataService,\r\n private productDetailService: ProductDetailService,\r\n private notificationService: NotificationService,\r\n private modalService: ModalService,\r\n ) {}\r\n\r\n ngOnInit() {\r\n this.initOptionsAndVariants();\r\n this.languageCode =\r\n (this.route.snapshot.paramMap.get('lang') as LanguageCode) || getDefaultUiLanguage();\r\n this.dataService.settings.getActiveChannel().single$.subscribe(data => {\r\n this.currencyCode = data.activeChannel.currencyCode;\r\n });\r\n }\r\n\r\n onFormChanged(variantInfo: GeneratedVariant) {\r\n this.formValueChanged = true;\r\n variantInfo.enabled = true;\r\n }\r\n\r\n canDeactivate(): boolean {\r\n return !this.formValueChanged;\r\n }\r\n\r\n getVariantsToAdd() {\r\n return this.generatedVariants.filter(v => !v.existing && v.enabled);\r\n }\r\n\r\n getVariantName(variant: GeneratedVariant) {\r\n return variant.options.length === 0\r\n ? _('catalog.default-variant')\r\n : variant.options.map(o => o.name).join(' ');\r\n }\r\n\r\n addOptionGroup() {\r\n this.optionGroups.push({\r\n isNew: true,\r\n locked: false,\r\n name: '',\r\n values: [],\r\n });\r\n this.optionsChanged = true;\r\n }\r\n\r\n removeOptionGroup(optionGroup: OptionGroupUiModel) {\r\n const id = optionGroup.id;\r\n if (optionGroup.isNew) {\r\n this.optionGroups = this.optionGroups.filter(og => og !== optionGroup);\r\n this.generateVariants();\r\n this.optionsChanged = true;\r\n } else if (id) {\r\n this.modalService\r\n .dialog({\r\n title: _('catalog.confirm-delete-product-option-group'),\r\n translationVars: { name: optionGroup.name },\r\n buttons: [\r\n { type: 'secondary', label: _('common.cancel') },\r\n { type: 'danger', label: _('common.delete'), returnValue: true },\r\n ],\r\n })\r\n .pipe(\r\n switchMap(val => {\r\n if (val) {\r\n return this.dataService.product.removeOptionGroupFromProduct({\r\n optionGroupId: id,\r\n productId: this.product.id,\r\n });\r\n } else {\r\n return EMPTY;\r\n }\r\n }),\r\n )\r\n .subscribe(({ removeOptionGroupFromProduct }) => {\r\n if (removeOptionGroupFromProduct.__typename === 'Product') {\r\n this.notificationService.success(_('common.notify-delete-success'), {\r\n entity: 'ProductOptionGroup',\r\n });\r\n this.initOptionsAndVariants();\r\n this.optionsChanged = true;\r\n } else if (removeOptionGroupFromProduct.__typename === 'ProductOptionInUseError') {\r\n this.notificationService.error(removeOptionGroupFromProduct.message ?? '');\r\n }\r\n });\r\n }\r\n }\r\n\r\n addOption(index: number, optionName: string) {\r\n const group = this.optionGroups[index];\r\n if (group) {\r\n group.values.push({ name: optionName, locked: false });\r\n this.generateVariants();\r\n this.optionsChanged = true;\r\n }\r\n }\r\n\r\n removeOption(index: number, { id, name }: { id?: string; name: string }) {\r\n const optionGroup = this.optionGroups[index];\r\n if (optionGroup) {\r\n if (!id) {\r\n optionGroup.values = optionGroup.values.filter(v => v.name !== name);\r\n this.generateVariants();\r\n } else {\r\n this.modalService\r\n .dialog({\r\n title: _('catalog.confirm-delete-product-option'),\r\n translationVars: { name },\r\n buttons: [\r\n { type: 'secondary', label: _('common.cancel') },\r\n { type: 'danger', label: _('common.delete'), returnValue: true },\r\n ],\r\n })\r\n .pipe(\r\n switchMap(val => {\r\n if (val) {\r\n return this.dataService.product.deleteProductOption(id);\r\n } else {\r\n return EMPTY;\r\n }\r\n }),\r\n )\r\n .subscribe(({ deleteProductOption }) => {\r\n if (deleteProductOption.result === DeletionResult.DELETED) {\r\n this.notificationService.success(_('common.notify-delete-success'), {\r\n entity: 'ProductOption',\r\n });\r\n optionGroup.values = optionGroup.values.filter(v => v.id !== id);\r\n this.generateVariants();\r\n this.optionsChanged = true;\r\n } else {\r\n this.notificationService.error(deleteProductOption.message ?? '');\r\n }\r\n });\r\n }\r\n }\r\n }\r\n\r\n generateVariants() {\r\n const groups = this.optionGroups.map(g => g.values);\r\n const previousVariants = this.generatedVariants;\r\n const generatedVariantFactory = (\r\n isDefault: boolean,\r\n options: GeneratedVariant['options'],\r\n existingVariant?: NonNullable<GetProductVariantOptionsQuery['product']>['variants'][number],\r\n prototypeVariant?: NonNullable<GetProductVariantOptionsQuery['product']>['variants'][number],\r\n ): GeneratedVariant => {\r\n const prototype = this.getVariantPrototype(options, previousVariants);\r\n return new GeneratedVariant({\r\n enabled: true,\r\n existing: !!existingVariant,\r\n productVariantId: existingVariant?.id,\r\n isDefault,\r\n options,\r\n price: existingVariant?.price ?? prototypeVariant?.price ?? prototype.price,\r\n sku: existingVariant?.sku ?? prototypeVariant?.sku ?? prototype.sku,\r\n stock: existingVariant?.stockOnHand ?? prototypeVariant?.stockOnHand ?? prototype.stock,\r\n });\r\n };\r\n this.generatedVariants = groups.length\r\n ? generateAllCombinations(groups).map(options => {\r\n const existingVariant = this.product.variants.find(v =>\r\n this.optionsAreEqual(v.options, options),\r\n );\r\n const prototypeVariant = this.product.variants.find(v =>\r\n this.optionsAreSubset(v.options, options),\r\n );\r\n return generatedVariantFactory(false, options, existingVariant, prototypeVariant);\r\n })\r\n : [generatedVariantFactory(true, [], this.product.variants[0])];\r\n }\r\n\r\n /**\r\n * Returns one of the existing variants to base the newly-generated variant's\r\n * details off.\r\n */\r\n private getVariantPrototype(\r\n options: GeneratedVariant['options'],\r\n previousVariants: GeneratedVariant[],\r\n ): Pick<GeneratedVariant, 'sku' | 'price' | 'stock'> {\r\n const variantsWithSimilarOptions = previousVariants.filter(v =>\r\n options.map(o => o.name).filter(name => v.options.map(o => o.name).includes(name)),\r\n );\r\n if (variantsWithSimilarOptions.length) {\r\n return pick(previousVariants[0], ['sku', 'price', 'stock']);\r\n }\r\n return {\r\n sku: '',\r\n price: 0,\r\n stock: 0,\r\n };\r\n }\r\n\r\n deleteVariant(id: string, options: GeneratedVariant['options']) {\r\n this.modalService\r\n .dialog({\r\n title: _('catalog.confirm-delete-product-variant'),\r\n translationVars: { name: options.map(o => o.name).join(' ') },\r\n buttons: [\r\n { type: 'secondary', label: _('common.cancel') },\r\n { type: 'danger', label: _('common.delete'), returnValue: true },\r\n ],\r\n })\r\n .pipe(\r\n switchMap(response =>\r\n response ? this.productDetailService.deleteProductVariant(id, this.product.id) : EMPTY,\r\n ),\r\n switchMap(() => this.reFetchProduct(null)),\r\n )\r\n .subscribe(\r\n () => {\r\n this.notificationService.success(_('common.notify-delete-success'), {\r\n entity: 'ProductVariant',\r\n });\r\n this.initOptionsAndVariants();\r\n },\r\n err => {\r\n this.notificationService.error(_('common.notify-delete-error'), {\r\n entity: 'ProductVariant',\r\n });\r\n },\r\n );\r\n }\r\n\r\n save() {\r\n this.optionGroups = this.optionGroups.filter(g => g.values.length);\r\n const newOptionGroups = this.optionGroups\r\n .filter(og => og.isNew)\r\n .map(og => ({\r\n name: og.name,\r\n values: [],\r\n }));\r\n\r\n this.checkUniqueSkus()\r\n .pipe(\r\n mergeMap(() => this.confirmDeletionOfObsoleteVariants()),\r\n mergeMap(() =>\r\n this.productDetailService.createProductOptionGroups(newOptionGroups, this.languageCode),\r\n ),\r\n mergeMap(createdOptionGroups => this.addOptionGroupsToProduct(createdOptionGroups)),\r\n mergeMap(createdOptionGroups => this.addNewOptionsToGroups(createdOptionGroups)),\r\n mergeMap(groupsIds => this.fetchOptionGroups(groupsIds)),\r\n mergeMap(groups => this.createNewProductVariants(groups)),\r\n mergeMap(res => this.deleteObsoleteVariants(res.createProductVariants)),\r\n mergeMap(variants => this.reFetchProduct(variants)),\r\n )\r\n .subscribe({\r\n next: variants => {\r\n this.formValueChanged = false;\r\n this.notificationService.success(_('catalog.created-new-variants-success'), {\r\n count: variants.length,\r\n });\r\n this.initOptionsAndVariants();\r\n this.optionsChanged = false;\r\n },\r\n });\r\n }\r\n\r\n private checkUniqueSkus() {\r\n const withDuplicateSkus = this.generatedVariants.filter((variant, index) => {\r\n return (\r\n variant.enabled &&\r\n this.generatedVariants.find(gv => gv.sku.trim() === variant.sku.trim() && gv !== variant)\r\n );\r\n });\r\n if (withDuplicateSkus.length) {\r\n return this.modalService\r\n .dialog({\r\n title: _('catalog.duplicate-sku-warning'),\r\n body: unique(withDuplicateSkus.map(v => `${v.sku}`)).join(', '),\r\n buttons: [{ label: _('common.close'), returnValue: false, type: 'primary' }],\r\n })\r\n .pipe(mergeMap(res => EMPTY));\r\n } else {\r\n return of(true);\r\n }\r\n }\r\n\r\n private confirmDeletionOfObsoleteVariants(): Observable<boolean> {\r\n const obsoleteVariants = this.getObsoleteVariants();\r\n if (obsoleteVariants.length) {\r\n return this.modalService\r\n .fromComponent(ConfirmVariantDeletionDialogComponent, {\r\n locals: {\r\n variants: obsoleteVariants,\r\n },\r\n })\r\n .pipe(\r\n mergeMap(res => {\r\n return res === true ? of(true) : EMPTY;\r\n }),\r\n );\r\n } else {\r\n return of(true);\r\n }\r\n }\r\n\r\n private getObsoleteVariants() {\r\n return this.product.variants.filter(\r\n variant => !this.generatedVariants.find(gv => gv.productVariantId === variant.id),\r\n );\r\n }\r\n\r\n private hasOnlyDefaultVariant(product: NonNullable<GetProductVariantOptionsQuery['product']>): boolean {\r\n return product.variants.length === 1 && product.optionGroups.length === 0;\r\n }\r\n\r\n private addOptionGroupsToProduct(\r\n createdOptionGroups: Array<CreateProductOptionGroupMutation['createProductOptionGroup']>,\r\n ): Observable<Array<CreateProductOptionGroupMutation['createProductOptionGroup']>> {\r\n if (createdOptionGroups.length) {\r\n return forkJoin(\r\n createdOptionGroups.map(optionGroup => {\r\n return this.dataService.product.addOptionGroupToProduct({\r\n productId: this.product.id,\r\n optionGroupId: optionGroup.id,\r\n });\r\n }),\r\n ).pipe(map(() => createdOptionGroups));\r\n } else {\r\n return of([]);\r\n }\r\n }\r\n\r\n private addNewOptionsToGroups(\r\n createdOptionGroups: Array<CreateProductOptionGroupMutation['createProductOptionGroup']>,\r\n ): Observable<string[]> {\r\n const newOptions: CreateProductOptionInput[] = this.optionGroups\r\n .map(og => {\r\n const createdGroup = createdOptionGroups.find(cog => cog.name === og.name);\r\n const productOptionGroupId = createdGroup ? createdGroup.id : og.id;\r\n if (!productOptionGroupId) {\r\n throw new Error('Could not get a productOptionGroupId');\r\n }\r\n return og.values\r\n .filter(v => !v.locked)\r\n .map(v => ({\r\n productOptionGroupId,\r\n code: normalizeString(v.name, '-'),\r\n translations: [{ name: v.name, languageCode: this.languageCode }],\r\n }));\r\n })\r\n .reduce((flat, options) => [...flat, ...options], []);\r\n\r\n const allGroupIds = [\r\n ...createdOptionGroups.map(g => g.id),\r\n ...this.optionGroups.map(g => g.id).filter(notNullOrUndefined),\r\n ];\r\n\r\n if (newOptions.length) {\r\n return forkJoin(newOptions.map(input => this.dataService.product.addOptionToGroup(input))).pipe(\r\n map(() => allGroupIds),\r\n );\r\n } else {\r\n return of(allGroupIds);\r\n }\r\n }\r\n\r\n private fetchOptionGroups(groupsIds: string[]): Observable<ProductOptionGroupWithOptionsFragment[]> {\r\n return forkJoin(\r\n groupsIds.map(id =>\r\n this.dataService.product\r\n .getProductOptionGroup(id)\r\n .mapSingle(data => data.productOptionGroup)\r\n .pipe(filter(notNullOrUndefined)),\r\n ),\r\n ).pipe(defaultIfEmpty([] as ProductOptionGroupWithOptionsFragment[]));\r\n }\r\n\r\n private createNewProductVariants(groups: ProductOptionGroupWithOptionsFragment[]) {\r\n const options = groups\r\n .filter(notNullOrUndefined)\r\n .map(og => og.options)\r\n .reduce((flat, o) => [...flat, ...o], []);\r\n const variants = this.generatedVariants\r\n .filter(v => v.enabled && !v.existing)\r\n .map(v => {\r\n const optionIds = groups.map((group, index) => {\r\n const option = group.options.find(o => o.name === v.options[index].name);\r\n if (option) {\r\n return option.id;\r\n } else {\r\n throw new Error(`Could not find a matching option for group ${group.name}`);\r\n }\r\n });\r\n return {\r\n price: v.price,\r\n sku: v.sku,\r\n stock: v.stock,\r\n optionIds,\r\n };\r\n });\r\n return this.productDetailService.createProductVariants(\r\n this.product,\r\n variants,\r\n options,\r\n this.languageCode,\r\n );\r\n }\r\n\r\n private deleteObsoleteVariants<T>(input: T): Observable<T | T[]> {\r\n const obsoleteVariants = this.getObsoleteVariants();\r\n if (obsoleteVariants.length) {\r\n const deleteOperations = obsoleteVariants.map(v =>\r\n this.dataService.product.deleteProductVariant(v.id).pipe(map(() => input)),\r\n );\r\n return forkJoin(...deleteOperations);\r\n } else {\r\n return of(input);\r\n }\r\n }\r\n\r\n private reFetchProduct<T>(input: T): Observable<T> {\r\n // Re-fetch the Product to force an update to the view.\r\n const id = this.route.snapshot.paramMap.get('id');\r\n if (id) {\r\n return this.dataService.product.getProduct(id).single$.pipe(map(() => input));\r\n } else {\r\n return of(input);\r\n }\r\n }\r\n\r\n initOptionsAndVariants() {\r\n this.dataService.product\r\n // tslint:disable-next-line:no-non-null-assertion\r\n .getProductVariantsOptions(this.route.snapshot.paramMap.get('id')!)\r\n // tslint:disable-next-line:no-non-null-assertion\r\n .mapSingle(({ product }) => product!)\r\n .subscribe(p => {\r\n this.product = p;\r\n const allUsedOptionIds = p.variants.map(v => v.options.map(option => option.id)).flat();\r\n const allUsedOptionGroupIds = p.variants\r\n .map(v => v.options.map(option => option.groupId))\r\n .flat();\r\n this.optionGroups = p.optionGroups.map(og => {\r\n return {\r\n id: og.id,\r\n isNew: false,\r\n name: og.name,\r\n locked: allUsedOptionGroupIds.includes(og.id),\r\n values: og.options.map(o => ({\r\n id: o.id,\r\n name: o.name,\r\n locked: allUsedOptionIds.includes(o.id),\r\n })),\r\n };\r\n });\r\n this.generateVariants();\r\n });\r\n }\r\n\r\n private optionsAreEqual(a: Array<{ name: string }>, b: Array<{ name: string }>): boolean {\r\n return this.toOptionString(a) === this.toOptionString(b);\r\n }\r\n\r\n private optionsAreSubset(a: Array<{ name: string }>, b: Array<{ name: string }>): boolean {\r\n return this.toOptionString(b).includes(this.toOptionString(a));\r\n }\r\n\r\n private toOptionString(o: Array<{ name: string }>): string {\r\n return o\r\n .map(x => x.name)\r\n .sort()\r\n .join('|');\r\n }\r\n}\r\n","import { Injectable } from '@angular/core';\r\nimport { Router } from '@angular/router';\r\nimport { AssetFragment, AssetType, BaseEntityResolver, DataService } from '@vendure/admin-ui/core';\r\n\r\n@Injectable({\r\n providedIn: 'root',\r\n})\r\nexport class AssetResolver extends BaseEntityResolver<AssetFragment> {\r\n constructor(router: Router, dataService: DataService) {\r\n super(\r\n router,\r\n {\r\n __typename: 'Asset' as const,\r\n id: '',\r\n createdAt: '',\r\n updatedAt: '',\r\n name: '',\r\n type: AssetType.IMAGE,\r\n fileSize: 0,\r\n mimeType: '',\r\n width: 0,\r\n height: 0,\r\n source: '',\r\n preview: '',\r\n focalPoint: null,\r\n },\r\n id => dataService.product.getAsset(id).mapStream(data => data.asset),\r\n );\r\n }\r\n}\r\n","import { Injectable } from '@angular/core';\r\nimport { Router } from '@angular/router';\r\nimport {\r\n BaseEntityResolver,\r\n CollectionFragment,\r\n DataService,\r\n getDefaultUiLanguage,\r\n} from '@vendure/admin-ui/core';\r\n\r\n@Injectable({\r\n providedIn: 'root',\r\n})\r\nexport class CollectionResolver extends BaseEntityResolver<CollectionFragment> {\r\n constructor(router: Router, dataService: DataService) {\r\n super(\r\n router,\r\n {\r\n __typename: 'Collection' as 'Collection',\r\n id: '',\r\n createdAt: '',\r\n updatedAt: '',\r\n languageCode: getDefaultUiLanguage(),\r\n name: '',\r\n slug: '',\r\n isPrivate: false,\r\n breadcrumbs: [],\r\n description: '',\r\n featuredAsset: null,\r\n assets: [],\r\n translations: [],\r\n inheritFilters: true,\r\n filters: [],\r\n parent: {} as any,\r\n children: null,\r\n },\r\n id => dataService.collection.getCollection(id).mapStream(data => data.collection),\r\n );\r\n }\r\n}\r\n","import { Injectable } from '@angular/core';\r\nimport { Router } from '@angular/router';\r\nimport {\r\n BaseEntityResolver,\r\n DataService,\r\n FacetWithValuesFragment,\r\n getDefaultUiLanguage,\r\n} from '@vendure/admin-ui/core';\r\n\r\n@Injectable({\r\n providedIn: 'root',\r\n})\r\nexport class FacetResolver extends BaseEntityResolver<FacetWithValuesFragment> {\r\n constructor(router: Router, dataService: DataService) {\r\n super(\r\n router,\r\n {\r\n __typename: 'Facet' as 'Facet',\r\n id: '',\r\n createdAt: '',\r\n updatedAt: '',\r\n isPrivate: false,\r\n languageCode: getDefaultUiLanguage(),\r\n name: '',\r\n code: '',\r\n translations: [],\r\n values: [],\r\n },\r\n id => dataService.facet.getFacet(id).mapStream(data => data.facet),\r\n );\r\n }\r\n}\r\n","import { Injectable } from '@angular/core';\r\nimport { Router } from '@angular/router';\r\nimport {\r\n BaseEntityResolver,\r\n DataService,\r\n getDefaultUiLanguage,\r\n GetProductWithVariantsQuery,\r\n} from '@vendure/admin-ui/core';\r\n\r\n@Injectable({\r\n providedIn: 'root',\r\n})\r\nexport class ProductResolver extends BaseEntityResolver<GetProductWithVariantsQuery['product']> {\r\n constructor(dataService: DataService, router: Router) {\r\n super(\r\n router,\r\n {\r\n __typename: 'Product' as 'Product',\r\n id: '',\r\n createdAt: '',\r\n updatedAt: '',\r\n enabled: true,\r\n languageCode: getDefaultUiLanguage(),\r\n name: '',\r\n slug: '',\r\n featuredAsset: null,\r\n assets: [],\r\n description: '',\r\n translations: [],\r\n optionGroups: [],\r\n facetValues: [],\r\n variantList: { items: [], totalItems: 0 },\r\n channels: [],\r\n },\r\n id =>\r\n dataService.product\r\n .getProduct(id, { take: 10 })\r\n .refetchOnChannelChange()\r\n .mapStream(data => data.product),\r\n );\r\n }\r\n}\r\n","import { Injectable } from '@angular/core';\r\nimport { Router } from '@angular/router';\r\nimport { BaseEntityResolver } from '@vendure/admin-ui/core';\r\nimport { GetProductVariantOptionsQuery } from '@vendure/admin-ui/core';\r\nimport { DataService } from '@vendure/admin-ui/core';\r\n\r\n@Injectable({\r\n providedIn: 'root',\r\n})\r\nexport class ProductVariantsResolver extends BaseEntityResolver<GetProductVariantOptionsQuery['product']> {\r\n constructor(router: Router, dataService: DataService) {\r\n super(\r\n router,\r\n {\r\n __typename: 'Product' as 'Product',\r\n id: '',\r\n createdAt: '',\r\n updatedAt: '',\r\n name: '',\r\n optionGroups: [],\r\n variants: [],\r\n },\r\n id => dataService.product.getProductVariantsOptions(id).mapStream(data => data.product),\r\n );\r\n }\r\n}\r\n","import { Route } from '@angular/router';\r\nimport { marker as _ } from '@biesbjerg/ngx-translate-extract-marker';\r\nimport {\r\n AssetFragment,\r\n CanDeactivateDetailGuard,\r\n CollectionFragment,\r\n createResolveData,\r\n detailBreadcrumb,\r\n FacetWithValuesFragment,\r\n GetProductWithVariantsQuery,\r\n} from '@vendure/admin-ui/core';\r\nimport { map } from 'rxjs/operators';\r\n\r\nimport { AssetDetailComponent } from './components/asset-detail/asset-detail.component';\r\nimport { AssetListComponent } from './components/asset-list/asset-list.component';\r\nimport { CollectionDetailComponent } from './components/collection-detail/collection-detail.component';\r\nimport { CollectionListComponent } from './components/collection-list/collection-list.component';\r\nimport { FacetDetailComponent } from './components/facet-detail/facet-detail.component';\r\nimport { FacetListComponent } from './components/facet-list/facet-list.component';\r\nimport { ProductDetailComponent } from './components/product-detail/product-detail.component';\r\nimport { ProductListComponent } from './components/product-list/product-list.component';\r\nimport { ProductOptionsEditorComponent } from './components/product-options-editor/product-options-editor.component';\r\nimport { ProductVariantsEditorComponent } from './components/product-variants-editor/product-variants-editor.component';\r\nimport { AssetResolver } from './providers/routing/asset-resolver';\r\nimport { CollectionResolver } from './providers/routing/collection-resolver';\r\nimport { FacetResolver } from './providers/routing/facet-resolver';\r\nimport { ProductResolver } from './providers/routing/product-resolver';\r\nimport { ProductVariantsResolver } from './providers/routing/product-variants-resolver';\r\n\r\nexport const catalogRoutes: Route[] = [\r\n {\r\n path: 'products',\r\n component: ProductListComponent,\r\n data: {\r\n breadcrumb: _('breadcrumb.products'),\r\n },\r\n },\r\n {\r\n path: 'products/:id',\r\n component: ProductDetailComponent,\r\n resolve: createResolveData(ProductResolver),\r\n canDeactivate: [CanDeactivateDetailGuard],\r\n data: {\r\n breadcrumb: productBreadcrumb,\r\n },\r\n },\r\n {\r\n path: 'products/:id/manage-variants',\r\n component: ProductVariantsEditorComponent,\r\n resolve: createResolveData(ProductVariantsResolver),\r\n canDeactivate: [CanDeactivateDetailGuard],\r\n data: {\r\n breadcrumb: productVariantEditorBreadcrumb,\r\n },\r\n },\r\n {\r\n path: 'products/:id/options',\r\n component: ProductOptionsEditorComponent,\r\n resolve: createResolveData(ProductVariantsResolver),\r\n canDeactivate: [CanDeactivateDetailGuard],\r\n data: {\r\n breadcrumb: productOptionsEditorBreadcrumb,\r\n },\r\n },\r\n {\r\n path: 'facets',\r\n component: FacetListComponent,\r\n data: {\r\n breadcrumb: _('breadcrumb.facets'),\r\n },\r\n },\r\n {\r\n path: 'facets/:id',\r\n component: FacetDetailComponent,\r\n resolve: createResolveData(FacetResolver),\r\n canDeactivate: [CanDeactivateDetailGuard],\r\n data: {\r\n breadcrumb: facetBreadcrumb,\r\n },\r\n },\r\n {\r\n path: 'collections',\r\n component: CollectionListComponent,\r\n data: {\r\n breadcrumb: _('breadcrumb.collections'),\r\n },\r\n },\r\n {\r\n path: 'collections/:id',\r\n component: CollectionDetailComponent,\r\n resolve: createResolveData(CollectionResolver),\r\n canDeactivate: [CanDeactivateDetailGuard],\r\n data: {\r\n breadcrumb: collectionBreadcrumb,\r\n },\r\n },\r\n {\r\n path: 'assets',\r\n component: AssetListComponent,\r\n data: {\r\n breadcrumb: _('breadcrumb.assets'),\r\n },\r\n },\r\n {\r\n path: 'assets/:id',\r\n component: AssetDetailComponent,\r\n resolve: createResolveData(AssetResolver),\r\n data: {\r\n breadcrumb: assetBreadcrumb,\r\n },\r\n },\r\n];\r\n\r\nexport function productBreadcrumb(data: any, params: any) {\r\n return detailBreadcrumb<NonNullable<GetProductWithVariantsQuery['product']>>({\r\n entity: data.entity,\r\n id: params.id,\r\n breadcrumbKey: 'breadcrumb.products',\r\n getName: product => product.name,\r\n route: 'products',\r\n });\r\n}\r\n\r\nexport function productVariantEditorBreadcrumb(data: any, params: any) {\r\n return data.entity.pipe(\r\n map((entity: any) => {\r\n return [\r\n {\r\n label: _('breadcrumb.products'),\r\n link: ['../', 'products'],\r\n },\r\n {\r\n label: `${entity.name}`,\r\n link: ['../', 'products', params.id, { tab: 'variants' }],\r\n },\r\n {\r\n label: _('breadcrumb.manage-variants'),\r\n link: ['manage-variants'],\r\n },\r\n ];\r\n }),\r\n );\r\n}\r\n\r\nexport function productOptionsEditorBreadcrumb(data: any, params: any) {\r\n return data.entity.pipe(\r\n map((entity: any) => {\r\n return [\r\n {\r\n label: _('breadcrumb.products'),\r\n link: ['../', 'products'],\r\n },\r\n {\r\n label: `${entity.name}`,\r\n link: ['../', 'products', params.id, { tab: 'variants' }],\r\n },\r\n {\r\n label: _('breadcrumb.product-options'),\r\n link: ['options'],\r\n },\r\n ];\r\n }),\r\n );\r\n}\r\n\r\nexport function facetBreadcrumb(data: any, params: any) {\r\n return detailBreadcrumb<FacetWithValuesFragment>({\r\n entity: data.entity,\r\n id: params.id,\r\n breadcrumbKey: 'breadcrumb.facets',\r\n getName: facet => facet.name,\r\n route: 'facets',\r\n });\r\n}\r\n\r\nexport function collectionBreadcrumb(data: any, params: any) {\r\n return detailBreadcrumb<CollectionFragment>({\r\n entity: data.entity,\r\n id: params.id,\r\n breadcrumbKey: 'breadcrumb.collections',\r\n getName: collection => collection.name,\r\n route: 'collections',\r\n });\r\n}\r\n\r\nexport function assetBreadcrumb(data: any, params: any) {\r\n return detailBreadcrumb<AssetFragment>({\r\n entity: data.entity,\r\n id: params.id,\r\n breadcrumbKey: 'breadcrumb.assets',\r\n getName: asset => asset.name,\r\n route: 'assets',\r\n });\r\n}\r\n","<ng-template vdrDialogTitle>\r\n {{ 'catalog.assign-to-channel' | translate }}\r\n</ng-template>\r\n<clr-input-container class=\"mb4\">\r\n <label>{{ 'common.channel' | translate }}</label>\r\n <vdr-channel-assignment-control\r\n clrInput\r\n [multiple]=\"false\"\r\n [includeDefaultChannel]=\"false\"\r\n [formControl]=\"selectedChannelIdControl\"\r\n ></vdr-channel-assignment-control>\r\n</clr-input-container>\r\n\r\n<ng-template vdrDialogButtons>\r\n <button type=\"button\" class=\"btn\" (click)=\"cancel()\">{{ 'common.cancel' | translate }}</button>\r\n <button type=\"submit\" (click)=\"assign()\" [disabled]=\"!selectedChannel\" class=\"btn btn-primary\">\r\n <ng-template [ngIf]=\"selectedChannel\" [ngIfElse]=\"noSelection\">\r\n {{ 'catalog.assign-to-named-channel' | translate: { channelCode: selectedChannel?.code } }}\r\n </ng-template>\r\n <ng-template #noSelection>\r\n {{ 'catalog.no-channel-selected' | translate }}\r\n </ng-template>\r\n </button>\r\n</ng-template>\r\n","import { ChangeDetectionStrategy, Component, OnInit } from '@angular/core';\r\nimport { FormControl } from '@angular/forms';\r\nimport { DataService, Dialog, GetChannelsQuery, ItemOf, NotificationService } from '@vendure/admin-ui/core';\r\nimport { combineLatest } from 'rxjs';\r\n\r\ntype Channel = GetChannelsQuery['channels'][number];\r\n\r\n@Component({\r\n selector: 'vdr-assign-to-channel-dialog',\r\n templateUrl: './assign-to-channel-dialog.component.html',\r\n styleUrls: ['./assign-to-channel-dialog.component.scss'],\r\n changeDetection: ChangeDetectionStrategy.OnPush,\r\n})\r\nexport class AssignToChannelDialogComponent implements OnInit, Dialog<Channel> {\r\n selectedChannel: Channel | null | undefined;\r\n currentChannel: Channel;\r\n availableChannels: Channel[];\r\n resolveWith: (result?: Channel) => void;\r\n selectedChannelIdControl = new FormControl();\r\n\r\n // assigned by ModalService.fromComponent() call\r\n\r\n constructor(private dataService: DataService, private notificationService: NotificationService) {}\r\n\r\n ngOnInit() {\r\n const activeChannelId$ = this.dataService.client\r\n .userStatus()\r\n .mapSingle(({ userStatus }) => userStatus.activeChannelId);\r\n const allChannels$ = this.dataService.settings.getChannels().mapSingle(data => data.channels);\r\n\r\n combineLatest(activeChannelId$, allChannels$).subscribe(([activeChannelId, channels]) => {\r\n // tslint:disable-next-line:no-non-null-assertion\r\n this.currentChannel = channels.find(c => c.id === activeChannelId)!;\r\n this.availableChannels = channels;\r\n });\r\n\r\n this.selectedChannelIdControl.valueChanges.subscribe(ids => {\r\n this.selectChannel(ids);\r\n });\r\n }\r\n\r\n selectChannel(channelIds: string[]) {\r\n this.selectedChannel = this.availableChannels.find(c => c.id === channelIds[0]);\r\n }\r\n\r\n assign() {\r\n const selectedChannel = this.selectedChannel;\r\n if (selectedChannel) {\r\n this.resolveWith(selectedChannel);\r\n }\r\n }\r\n\r\n cancel() {\r\n this.resolveWith();\r\n }\r\n}\r\n","import { gql } from 'apollo-angular';\r\n\r\nexport const GET_PRODUCTS_WITH_FACET_VALUES_BY_IDS = gql`\r\n query GetProductsWithFacetValuesByIds($ids: [String!]!) {\r\n products(options: { filter: { id: { in: $ids } } }) {\r\n items {\r\n id\r\n name\r\n facetValues {\r\n id\r\n name\r\n code\r\n facet {\r\n id\r\n name\r\n code\r\n }\r\n }\r\n }\r\n }\r\n }\r\n`;\r\n\r\nexport const GET_VARIANTS_WITH_FACET_VALUES_BY_IDS = gql`\r\n query GetVariantsWithFacetValuesByIds($ids: [String!]!) {\r\n productVariants(options: { filter: { id: { in: $ids } } }) {\r\n items {\r\n id\r\n name\r\n sku\r\n facetValues {\r\n id\r\n name\r\n code\r\n facet {\r\n id\r\n name\r\n code\r\n }\r\n }\r\n }\r\n }\r\n }\r\n`;\r\n\r\nexport const UPDATE_PRODUCTS_BULK = gql`\r\n mutation UpdateProductsBulk($input: [UpdateProductInput!]!) {\r\n updateProducts(input: $input) {\r\n id\r\n name\r\n facetValues {\r\n id\r\n name\r\n code\r\n }\r\n }\r\n }\r\n`;\r\n\r\nexport const UPDATE_VARIANTS_BULK = gql`\r\n mutation UpdateVariantsBulk($input: [UpdateProductVariantInput!]!) {\r\n updateProductVariants(input: $input) {\r\n id\r\n name\r\n facetValues {\r\n id\r\n name\r\n code\r\n }\r\n }\r\n }\r\n`;\r\n","<ng-template vdrDialogTitle>\r\n {{ 'catalog.edit-facet-values' | translate }}\r\n</ng-template>\r\n\r\n<div class=\"flex\">\r\n <div class=\"flex center\">\r\n <div class=\"mr2\">\r\n {{ 'catalog.add-facet-value' | translate }}\r\n </div>\r\n <vdr-facet-value-selector\r\n (selectedValuesChange)=\"selectedValues = $event\"\r\n ></vdr-facet-value-selector>\r\n </div>\r\n</div>\r\n\r\n<table class=\"table\" *ngIf=\"state !== 'loading'; else placeholder\">\r\n <tbody>\r\n <tr *ngFor=\"let item of items\">\r\n <td class=\"left align-middle\">\r\n <div>{{ item.name }}</div>\r\n <div *ngIf=\"item.sku\" class=\"sku\">{{ item.sku }}</div>\r\n </td>\r\n <td class=\"left\">\r\n <vdr-facet-value-chip\r\n *ngFor=\"let facetValue of item.facetValues\"\r\n [facetValue]=\"facetValue\"\r\n (remove)=\"removeFacetValue(item, facetValue.id)\"\r\n ></vdr-facet-value-chip>\r\n </td>\r\n </tr>\r\n </tbody>\r\n</table>\r\n\r\n<ng-template #placeholder>\r\n <div class=\"loading\">\r\n <clr-spinner></clr-spinner>\r\n </div>\r\n</ng-template>\r\n\r\n<ng-template vdrDialogButtons>\r\n <button type=\"button\" class=\"btn\" (click)=\"cancel()\">{{ 'common.cancel' | translate }}</button>\r\n <button\r\n type=\"submit\"\r\n (click)=\"addFacetValues()\"\r\n [disabled]=\"selectedValues.length === 0 && facetValuesRemoved === false\"\r\n class=\"btn btn-primary\"\r\n >\r\n {{ 'common.update' | translate }}\r\n </button>\r\n</ng-template>\r\n","import { ChangeDetectionStrategy, ChangeDetectorRef, Component, OnDestroy, OnInit } from '@angular/core';\r\nimport {\r\n DataService,\r\n Dialog,\r\n FacetWithValuesFragment,\r\n GetProductsWithFacetValuesByIdsQuery,\r\n GetProductsWithFacetValuesByIdsQueryVariables,\r\n GetVariantsWithFacetValuesByIdsQuery,\r\n UpdateProductsBulkMutation,\r\n UpdateProductsBulkMutationVariables,\r\n UpdateVariantsBulkMutation,\r\n UpdateVariantsBulkMutationVariables,\r\n} from '@vendure/admin-ui/core';\r\nimport { unique } from '@vendure/common/lib/unique';\r\nimport { Observable, Subscription } from 'rxjs';\r\nimport { shareReplay, switchMap } from 'rxjs/operators';\r\n\r\nimport {\r\n GET_PRODUCTS_WITH_FACET_VALUES_BY_IDS,\r\n GET_VARIANTS_WITH_FACET_VALUES_BY_IDS,\r\n UPDATE_PRODUCTS_BULK,\r\n UPDATE_VARIANTS_BULK,\r\n} from './bulk-add-facet-values-dialog.graphql';\r\n\r\ninterface ProductOrVariant {\r\n id: string;\r\n name: string;\r\n sku?: string;\r\n facetValues: Array<{\r\n id: string;\r\n name: string;\r\n code: string;\r\n facet: Array<{\r\n id: string;\r\n name: string;\r\n code: string;\r\n }>;\r\n }>;\r\n}\r\n\r\n@Component({\r\n selector: 'vdr-bulk-add-facet-values-dialog',\r\n templateUrl: './bulk-add-facet-values-dialog.component.html',\r\n styleUrls: ['./bulk-add-facet-values-dialog.component.scss'],\r\n changeDetection: ChangeDetectionStrategy.OnPush,\r\n})\r\nexport class BulkAddFacetValuesDialogComponent\r\n implements OnInit, OnDestroy, Dialog<FacetWithValuesFragment[]>\r\n{\r\n resolveWith: (result?: FacetWithValuesFragment[]) => void;\r\n /* provided by call to ModalService */\r\n mode: 'product' | 'variant' = 'product';\r\n ids?: string[];\r\n state: 'loading' | 'ready' | 'saving' = 'loading';\r\n\r\n selectedValues: FacetWithValuesFragment[] = [];\r\n items: ProductOrVariant[] = [];\r\n facetValuesRemoved = false;\r\n private subscription: Subscription;\r\n constructor(private dataService: DataService, private changeDetectorRef: ChangeDetectorRef) {}\r\n\r\n ngOnInit(): void {\r\n const fetchData$: Observable<any> =\r\n this.mode === 'product'\r\n ? this.dataService\r\n .query<\r\n GetProductsWithFacetValuesByIdsQuery,\r\n GetProductsWithFacetValuesByIdsQueryVariables\r\n >(GET_PRODUCTS_WITH_FACET_VALUES_BY_IDS, {\r\n ids: this.ids ?? [],\r\n })\r\n .mapSingle(({ products }) =>\r\n products.items.map(p => ({ ...p, facetValues: [...p.facetValues] })),\r\n )\r\n : this.dataService\r\n .query<\r\n GetVariantsWithFacetValuesByIdsQuery,\r\n GetProductsWithFacetValuesByIdsQueryVariables\r\n >(GET_VARIANTS_WITH_FACET_VALUES_BY_IDS, {\r\n ids: this.ids ?? [],\r\n })\r\n .mapSingle(({ productVariants }) =>\r\n productVariants.items.map(p => ({ ...p, facetValues: [...p.facetValues] })),\r\n );\r\n this.subscription = fetchData$.subscribe({\r\n next: items => {\r\n this.items = items;\r\n this.state = 'ready';\r\n this.changeDetectorRef.markForCheck();\r\n },\r\n });\r\n }\r\n\r\n ngOnDestroy() {\r\n this.subscription?.unsubscribe();\r\n }\r\n\r\n cancel() {\r\n this.resolveWith();\r\n }\r\n\r\n removeFacetValue(item: ProductOrVariant, facetValueId: string) {\r\n item.facetValues = item.facetValues.filter(fv => fv.id !== facetValueId);\r\n this.facetValuesRemoved = true;\r\n }\r\n\r\n addFacetValues() {\r\n const selectedFacetValueIds = this.selectedValues.map(sv => sv.id);\r\n this.state = 'saving';\r\n const save$: Observable<any> =\r\n this.mode === 'product'\r\n ? this.dataService.mutate<UpdateProductsBulkMutation, UpdateProductsBulkMutationVariables>(\r\n UPDATE_PRODUCTS_BULK,\r\n {\r\n input: this.items?.map(product => ({\r\n id: product.id,\r\n facetValueIds: unique([\r\n ...product.facetValues.map(fv => fv.id),\r\n ...selectedFacetValueIds,\r\n ]),\r\n })),\r\n },\r\n )\r\n : this.dataService.mutate<UpdateVariantsBulkMutation, UpdateVariantsBulkMutationVariables>(\r\n UPDATE_VARIANTS_BULK,\r\n {\r\n input: this.items?.map(product => ({\r\n id: product.id,\r\n facetValueIds: unique([\r\n ...product.facetValues.map(fv => fv.id),\r\n ...selectedFacetValueIds,\r\n ]),\r\n })),\r\n },\r\n );\r\n return save$.subscribe(result => {\r\n this.resolveWith(this.selectedValues);\r\n });\r\n }\r\n}\r\n","import { marker as _ } from '@biesbjerg/ngx-translate-extract-marker';\r\nimport {\r\n BulkAction,\r\n currentChannelIsNotDefault,\r\n DataService,\r\n DeletionResult,\r\n getChannelCodeFromUserStatus,\r\n isMultiChannel,\r\n ModalService,\r\n NotificationService,\r\n Permission,\r\n} from '@vendure/admin-ui/core';\r\nimport { unique } from '@vendure/common/lib/unique';\r\nimport { EMPTY, from, of } from 'rxjs';\r\nimport { mapTo, switchMap } from 'rxjs/operators';\r\n\r\nimport { AssignToChannelDialogComponent } from '../assign-to-channel-dialog/assign-to-channel-dialog.component';\r\nimport { CollectionPartial } from '../collection-tree/collection-tree.types';\r\n\r\nimport { CollectionListComponent } from './collection-list.component';\r\n\r\nexport const deleteCollectionsBulkAction: BulkAction<CollectionPartial, CollectionListComponent> = {\r\n location: 'collection-list',\r\n label: _('common.delete'),\r\n icon: 'trash',\r\n iconClass: 'is-danger',\r\n requiresPermission: userPermissions =>\r\n userPermissions.includes(Permission.DeleteCollection) ||\r\n userPermissions.includes(Permission.DeleteCatalog),\r\n onClick: ({ injector, selection, hostComponent, clearSelection }) => {\r\n const modalService = injector.get(ModalService);\r\n const dataService = injector.get(DataService);\r\n const notificationService = injector.get(NotificationService);\r\n\r\n modalService\r\n .dialog({\r\n title: _('catalog.confirm-bulk-delete-collections'),\r\n translationVars: {\r\n count: selection.length,\r\n },\r\n buttons: [\r\n { type: 'secondary', label: _('common.cancel') },\r\n { type: 'danger', label: _('common.delete'), returnValue: true },\r\n ],\r\n })\r\n .pipe(\r\n switchMap(response =>\r\n response\r\n ? dataService.collection.deleteCollections(unique(selection.map(c => c.id)))\r\n : EMPTY,\r\n ),\r\n )\r\n .subscribe(result => {\r\n let deleted = 0;\r\n const errors: string[] = [];\r\n for (const item of result.deleteCollections) {\r\n if (item.result === DeletionResult.DELETED) {\r\n deleted++;\r\n } else if (item.message) {\r\n errors.push(item.message);\r\n }\r\n }\r\n if (0 < deleted) {\r\n notificationService.success(_('catalog.notify-bulk-delete-collections-success'), {\r\n count: deleted,\r\n });\r\n }\r\n if (0 < errors.length) {\r\n notificationService.error(errors.join('\\n'));\r\n }\r\n hostComponent.refresh();\r\n clearSelection();\r\n });\r\n },\r\n};\r\n\r\nexport const assignCollectionsToChannelBulkAction: BulkAction<CollectionPartial, CollectionListComponent> = {\r\n location: 'collection-list',\r\n label: _('catalog.assign-to-channel'),\r\n icon: 'layers',\r\n requiresPermission: userPermissions =>\r\n userPermissions.includes(Permission.UpdateCatalog) ||\r\n userPermissions.includes(Permission.UpdateProduct),\r\n isVisible: ({ injector }) => isMultiChannel(injector.get(DataService)),\r\n onClick: ({ injector, selection, hostComponent, clearSelection }) => {\r\n const modalService = injector.get(ModalService);\r\n const dataService = injector.get(DataService);\r\n const notificationService = injector.get(NotificationService);\r\n modalService\r\n .fromComponent(AssignToChannelDialogComponent, {\r\n size: 'md',\r\n locals: {},\r\n })\r\n .pipe(\r\n switchMap(result => {\r\n if (result) {\r\n return dataService.collection\r\n .assignCollectionsToChannel({\r\n collectionIds: selection.map(c => c.id),\r\n channelId: result.id,\r\n })\r\n .pipe(mapTo(result));\r\n } else {\r\n return EMPTY;\r\n }\r\n }),\r\n )\r\n .subscribe(result => {\r\n notificationService.success(_('catalog.assign-collections-to-channel-success'), {\r\n count: selection.length,\r\n channelCode: result.code,\r\n });\r\n clearSelection();\r\n });\r\n },\r\n};\r\n\r\nexport const removeCollectionsFromChannelBulkAction: BulkAction<CollectionPartial, CollectionListComponent> =\r\n {\r\n location: 'collection-list',\r\n label: _('catalog.remove-from-channel'),\r\n requiresPermission: userPermissions =>\r\n userPermissions.includes(Permission.UpdateChannel) ||\r\n userPermissions.includes(Permission.UpdateProduct),\r\n getTranslationVars: ({ injector }) => getChannelCodeFromUserStatus(injector.get(DataService)),\r\n icon: 'layers',\r\n iconClass: 'is-warning',\r\n isVisible: ({ injector }) => currentChannelIsNotDefault(injector.get(DataService)),\r\n onClick: ({ injector, selection, hostComponent, clearSelection }) => {\r\n const modalService = injector.get(ModalService);\r\n const dataService = injector.get(DataService);\r\n const notificationService = injector.get(NotificationService);\r\n const activeChannelId$ = dataService.client\r\n .userStatus()\r\n .mapSingle(({ userStatus }) => userStatus.activeChannelId);\r\n\r\n from(getChannelCodeFromUserStatus(injector.get(DataService)))\r\n .pipe(\r\n switchMap(({ channelCode }) =>\r\n modalService.dialog({\r\n title: _('catalog.remove-from-channel'),\r\n translationVars: {\r\n channelCode,\r\n },\r\n buttons: [\r\n { type: 'secondary', label: _('common.cancel') },\r\n {\r\n type: 'danger',\r\n label: _('common.remove'),\r\n returnValue: true,\r\n },\r\n ],\r\n }),\r\n ),\r\n switchMap(res =>\r\n res\r\n ? activeChannelId$.pipe(\r\n switchMap(activeChannelId =>\r\n activeChannelId\r\n ? dataService.collection.removeCollectionsFromChannel({\r\n channelId: activeChannelId,\r\n collectionIds: selection.map(c => c.id),\r\n })\r\n : EMPTY,\r\n ),\r\n mapTo(true),\r\n )\r\n : of(false),\r\n ),\r\n )\r\n .subscribe(removed => {\r\n if (removed) {\r\n clearSelection();\r\n notificationService.success(\r\n _('catalog.notify-remove-collections-from-channel-success'),\r\n {\r\n count: selection.length,\r\n },\r\n );\r\n hostComponent.refresh();\r\n }\r\n });\r\n },\r\n };\r\n","import { marker as _ } from '@biesbjerg/ngx-translate-extract-marker';\r\nimport {\r\n BulkAction,\r\n currentChannelIsNotDefault,\r\n DataService,\r\n DeletionResult,\r\n getChannelCodeFromUserStatus,\r\n GetFacetListQuery,\r\n isMultiChannel,\r\n ItemOf,\r\n ModalService,\r\n NotificationService,\r\n Permission,\r\n} from '@vendure/admin-ui/core';\r\nimport { unique } from '@vendure/common/lib/unique';\r\nimport { EMPTY, of } from 'rxjs';\r\nimport { map, mapTo, switchMap } from 'rxjs/operators';\r\n\r\nimport { AssignToChannelDialogComponent } from '../assign-to-channel-dialog/assign-to-channel-dialog.component';\r\n\r\nimport { FacetListComponent } from './facet-list.component';\r\n\r\nexport const deleteFacetsBulkAction: BulkAction<ItemOf<GetFacetListQuery, 'facets'>, FacetListComponent> = {\r\n location: 'facet-list',\r\n label: _('common.delete'),\r\n icon: 'trash',\r\n iconClass: 'is-danger',\r\n requiresPermission: userPermissions =>\r\n userPermissions.includes(Permission.DeleteFacet) ||\r\n userPermissions.includes(Permission.DeleteCatalog),\r\n onClick: ({ injector, selection, hostComponent, clearSelection }) => {\r\n const modalService = injector.get(ModalService);\r\n const dataService = injector.get(DataService);\r\n const notificationService = injector.get(NotificationService);\r\n\r\n function showModalAndDelete(facetIds: string[], message?: string) {\r\n return modalService\r\n .dialog({\r\n title: _('catalog.confirm-bulk-delete-facets'),\r\n translationVars: {\r\n count: selection.length,\r\n },\r\n size: message ? 'lg' : 'md',\r\n body: message,\r\n buttons: [\r\n { type: 'secondary', label: _('common.cancel') },\r\n {\r\n type: 'danger',\r\n label: message ? _('common.force-delete') : _('common.delete'),\r\n returnValue: true,\r\n },\r\n ],\r\n })\r\n .pipe(\r\n switchMap(res =>\r\n res\r\n ? dataService.facet\r\n .deleteFacets(facetIds, !!message)\r\n .pipe(map(res2 => res2.deleteFacets))\r\n : of([]),\r\n ),\r\n );\r\n }\r\n\r\n showModalAndDelete(unique(selection.map(f => f.id)))\r\n .pipe(\r\n switchMap(result => {\r\n let deletedCount = 0;\r\n const errors: string[] = [];\r\n const errorIds: string[] = [];\r\n let i = 0;\r\n for (const item of result) {\r\n if (item.result === DeletionResult.DELETED) {\r\n deletedCount++;\r\n } else if (item.message) {\r\n errors.push(item.message);\r\n errorIds.push(selection[i]?.id);\r\n }\r\n i++;\r\n }\r\n if (0 < errorIds.length) {\r\n return showModalAndDelete(errorIds, errors.join('\\n')).pipe(\r\n map(result2 => {\r\n const deletedCount2 = result2.filter(\r\n r => r.result === DeletionResult.DELETED,\r\n ).length;\r\n return deletedCount + deletedCount2;\r\n }),\r\n );\r\n } else {\r\n return of(deletedCount);\r\n }\r\n }),\r\n )\r\n .subscribe(deletedCount => {\r\n if (deletedCount) {\r\n hostComponent.refresh();\r\n clearSelection();\r\n notificationService.success(_('catalog.notify-bulk-delete-facets-success'), {\r\n count: deletedCount,\r\n });\r\n }\r\n });\r\n },\r\n};\r\n\r\nexport const assignFacetsToChannelBulkAction: BulkAction<\r\n ItemOf<GetFacetListQuery, 'facets'>,\r\n FacetListComponent\r\n> = {\r\n location: 'facet-list',\r\n label: _('catalog.assign-to-channel'),\r\n icon: 'layers',\r\n requiresPermission: userPermissions =>\r\n userPermissions.includes(Permission.UpdateFacet) ||\r\n userPermissions.includes(Permission.UpdateCatalog),\r\n isVisible: ({ injector }) => isMultiChannel(injector.get(DataService)),\r\n onClick: ({ injector, selection, hostComponent, clearSelection }) => {\r\n const modalService = injector.get(ModalService);\r\n const dataService = injector.get(DataService);\r\n const notificationService = injector.get(NotificationService);\r\n modalService\r\n .fromComponent(AssignToChannelDialogComponent, {\r\n size: 'md',\r\n locals: {},\r\n })\r\n .pipe(\r\n switchMap(result => {\r\n if (result) {\r\n return dataService.facet\r\n .assignFacetsToChannel({\r\n facetIds: selection.map(f => f.id),\r\n channelId: result.id,\r\n })\r\n .pipe(mapTo(result));\r\n } else {\r\n return EMPTY;\r\n }\r\n }),\r\n )\r\n .subscribe(result => {\r\n notificationService.success(_('catalog.assign-facets-to-channel-success'), {\r\n count: selection.length,\r\n channelCode: result.code,\r\n });\r\n clearSelection();\r\n });\r\n },\r\n};\r\n\r\nexport const removeFacetsFromChannelBulkAction: BulkAction<\r\n ItemOf<GetFacetListQuery, 'facets'>,\r\n FacetListComponent\r\n> = {\r\n location: 'facet-list',\r\n label: _('catalog.remove-from-channel'),\r\n getTranslationVars: ({ injector }) => getChannelCodeFromUserStatus(injector.get(DataService)),\r\n icon: 'layers',\r\n iconClass: 'is-warning',\r\n requiresPermission: userPermissions =>\r\n userPermissions.includes(Permission.UpdateFacet) ||\r\n userPermissions.includes(Permission.UpdateCatalog),\r\n isVisible: ({ injector }) => currentChannelIsNotDefault(injector.get(DataService)),\r\n onClick: ({ injector, selection, hostComponent, clearSelection }) => {\r\n const modalService = injector.get(ModalService);\r\n const dataService = injector.get(DataService);\r\n const notificationService = injector.get(NotificationService);\r\n\r\n const activeChannelId$ = dataService.client\r\n .userStatus()\r\n .mapSingle(({ userStatus }) => userStatus.activeChannelId);\r\n\r\n function showModalAndDelete(facetIds: string[], message?: string) {\r\n return modalService\r\n .dialog({\r\n title: _('catalog.remove-from-channel'),\r\n translationVars: {\r\n count: selection.length,\r\n },\r\n size: message ? 'lg' : 'md',\r\n body: message,\r\n buttons: [\r\n { type: 'secondary', label: _('common.cancel') },\r\n {\r\n type: 'danger',\r\n label: message ? _('common.force-remove') : _('common.remove'),\r\n returnValue: true,\r\n },\r\n ],\r\n })\r\n .pipe(\r\n switchMap(res =>\r\n res\r\n ? activeChannelId$.pipe(\r\n switchMap(activeChannelId =>\r\n activeChannelId\r\n ? dataService.facet.removeFacetsFromChannel({\r\n channelId: activeChannelId,\r\n facetIds,\r\n force: !!message,\r\n })\r\n : EMPTY,\r\n ),\r\n map(res2 => res2.removeFacetsFromChannel),\r\n )\r\n : EMPTY,\r\n ),\r\n );\r\n }\r\n\r\n showModalAndDelete(unique(selection.map(f => f.id)))\r\n .pipe(\r\n switchMap(result => {\r\n let removedCount = selection.length;\r\n const errors: string[] = [];\r\n const errorIds: string[] = [];\r\n let i = 0;\r\n for (const item of result) {\r\n if (item.__typename === 'FacetInUseError') {\r\n errors.push(item.message);\r\n errorIds.push(selection[i]?.id);\r\n removedCount--;\r\n }\r\n i++;\r\n }\r\n if (0 < errorIds.length) {\r\n return showModalAndDelete(errorIds, errors.join('\\n')).pipe(\r\n map(result2 => {\r\n const notRemovedCount = result2.filter(\r\n r => r.__typename === 'FacetInUseError',\r\n ).length;\r\n return selection.length - notRemovedCount;\r\n }),\r\n );\r\n } else {\r\n return of(removedCount);\r\n }\r\n }),\r\n switchMap(removedCount =>\r\n removedCount\r\n ? getChannelCodeFromUserStatus(dataService).then(({ channelCode }) => ({\r\n channelCode,\r\n removedCount,\r\n }))\r\n : EMPTY,\r\n ),\r\n )\r\n .subscribe(({ removedCount, channelCode }) => {\r\n if (removedCount) {\r\n hostComponent.refresh();\r\n clearSelection();\r\n notificationService.success(_('catalog.notify-remove-facets-from-channel-success'), {\r\n count: removedCount,\r\n channelCode,\r\n });\r\n }\r\n });\r\n },\r\n};\r\n","import { marker as _ } from '@biesbjerg/ngx-translate-extract-marker';\r\nimport {\r\n BulkAction,\r\n currentChannelIsNotDefault,\r\n DataService,\r\n DeletionResult,\r\n getChannelCodeFromUserStatus,\r\n isMultiChannel,\r\n ModalService,\r\n NotificationService,\r\n Permission,\r\n} from '@vendure/admin-ui/core';\r\nimport { unique } from '@vendure/common/lib/unique';\r\nimport { EMPTY, from, of } from 'rxjs';\r\nimport { mapTo, switchMap } from 'rxjs/operators';\r\n\r\nimport { AssignProductsToChannelDialogComponent } from '../assign-products-to-channel-dialog/assign-products-to-channel-dialog.component';\r\nimport { BulkAddFacetValuesDialogComponent } from '../bulk-add-facet-values-dialog/bulk-add-facet-values-dialog.component';\r\n\r\nimport { ProductListComponent, SearchItem } from './product-list.component';\r\n\r\nexport const deleteProductsBulkAction: BulkAction<SearchItem, ProductListComponent> = {\r\n location: 'product-list',\r\n label: _('common.delete'),\r\n icon: 'trash',\r\n iconClass: 'is-danger',\r\n requiresPermission: userPermissions =>\r\n userPermissions.includes(Permission.DeleteProduct) ||\r\n userPermissions.includes(Permission.DeleteCatalog),\r\n onClick: ({ injector, selection, hostComponent, clearSelection }) => {\r\n const modalService = injector.get(ModalService);\r\n const dataService = injector.get(DataService);\r\n const notificationService = injector.get(NotificationService);\r\n modalService\r\n .dialog({\r\n title: _('catalog.confirm-bulk-delete-products'),\r\n translationVars: {\r\n count: selection.length,\r\n },\r\n buttons: [\r\n { type: 'secondary', label: _('common.cancel') },\r\n { type: 'danger', label: _('common.delete'), returnValue: true },\r\n ],\r\n })\r\n .pipe(\r\n switchMap(response =>\r\n response\r\n ? dataService.product.deleteProducts(unique(selection.map(p => p.productId)))\r\n : EMPTY,\r\n ),\r\n )\r\n .subscribe(result => {\r\n let deleted = 0;\r\n const errors: string[] = [];\r\n for (const item of result.deleteProducts) {\r\n if (item.result === DeletionResult.DELETED) {\r\n deleted++;\r\n } else if (item.message) {\r\n errors.push(item.message);\r\n }\r\n }\r\n if (0 < deleted) {\r\n notificationService.success(_('catalog.notify-bulk-delete-products-success'), {\r\n count: deleted,\r\n });\r\n }\r\n if (0 < errors.length) {\r\n notificationService.error(errors.join('\\n'));\r\n }\r\n hostComponent.refresh();\r\n clearSelection();\r\n });\r\n },\r\n};\r\n\r\nexport const assignProductsToChannelBulkAction: BulkAction<SearchItem, ProductListComponent> = {\r\n location: 'product-list',\r\n label: _('catalog.assign-to-channel'),\r\n icon: 'layers',\r\n requiresPermission: userPermissions =>\r\n userPermissions.includes(Permission.UpdateCatalog) ||\r\n userPermissions.includes(Permission.UpdateProduct),\r\n isVisible: ({ injector }) => isMultiChannel(injector.get(DataService)),\r\n onClick: ({ injector, selection, hostComponent, clearSelection }) => {\r\n const modalService = injector.get(ModalService);\r\n const dataService = injector.get(DataService);\r\n const notificationService = injector.get(NotificationService);\r\n modalService\r\n .fromComponent(AssignProductsToChannelDialogComponent, {\r\n size: 'lg',\r\n locals: {\r\n productIds: unique(selection.map(p => p.productId)),\r\n currentChannelIds: [],\r\n },\r\n })\r\n .subscribe(result => {\r\n if (result) {\r\n clearSelection();\r\n }\r\n });\r\n },\r\n};\r\n\r\nexport const removeProductsFromChannelBulkAction: BulkAction<SearchItem, ProductListComponent> = {\r\n location: 'product-list',\r\n label: _('catalog.remove-from-channel'),\r\n requiresPermission: userPermissions =>\r\n userPermissions.includes(Permission.UpdateChannel) ||\r\n userPermissions.includes(Permission.UpdateProduct),\r\n getTranslationVars: ({ injector }) => getChannelCodeFromUserStatus(injector.get(DataService)),\r\n icon: 'layers',\r\n iconClass: 'is-warning',\r\n isVisible: ({ injector }) => currentChannelIsNotDefault(injector.get(DataService)),\r\n onClick: ({ injector, selection, hostComponent, clearSelection }) => {\r\n const modalService = injector.get(ModalService);\r\n const dataService = injector.get(DataService);\r\n const notificationService = injector.get(NotificationService);\r\n const activeChannelId$ = dataService.client\r\n .userStatus()\r\n .mapSingle(({ userStatus }) => userStatus.activeChannelId);\r\n\r\n from(getChannelCodeFromUserStatus(injector.get(DataService)))\r\n .pipe(\r\n switchMap(({ channelCode }) =>\r\n modalService.dialog({\r\n title: _('catalog.remove-from-channel'),\r\n translationVars: {\r\n channelCode,\r\n },\r\n buttons: [\r\n { type: 'secondary', label: _('common.cancel') },\r\n {\r\n type: 'danger',\r\n label: _('common.remove'),\r\n returnValue: true,\r\n },\r\n ],\r\n }),\r\n ),\r\n switchMap(res =>\r\n res\r\n ? activeChannelId$.pipe(\r\n switchMap(activeChannelId =>\r\n activeChannelId\r\n ? dataService.product.removeProductsFromChannel({\r\n channelId: activeChannelId,\r\n productIds: selection.map(p => p.productId),\r\n })\r\n : EMPTY,\r\n ),\r\n mapTo(true),\r\n )\r\n : of(false),\r\n ),\r\n )\r\n .subscribe(removed => {\r\n if (removed) {\r\n clearSelection();\r\n notificationService.success(_('common.notify-remove-products-from-channel-success'), {\r\n count: selection.length,\r\n });\r\n setTimeout(() => hostComponent.refresh(), 1000);\r\n }\r\n });\r\n },\r\n};\r\n\r\nexport const assignFacetValuesToProductsBulkAction: BulkAction<SearchItem, ProductListComponent> = {\r\n location: 'product-list',\r\n label: _('catalog.edit-facet-values'),\r\n icon: 'tag',\r\n requiresPermission: userPermissions =>\r\n userPermissions.includes(Permission.UpdateCatalog) ||\r\n userPermissions.includes(Permission.UpdateProduct),\r\n onClick: ({ injector, selection, hostComponent, clearSelection }) => {\r\n const modalService = injector.get(ModalService);\r\n const dataService = injector.get(DataService);\r\n const notificationService = injector.get(NotificationService);\r\n const mode: 'product' | 'variant' = hostComponent.groupByProduct ? 'product' : 'variant';\r\n const ids =\r\n mode === 'product'\r\n ? unique(selection.map(p => p.productId))\r\n : unique(selection.map(p => p.productVariantId));\r\n return modalService\r\n .fromComponent(BulkAddFacetValuesDialogComponent, {\r\n size: 'xl',\r\n locals: {\r\n mode,\r\n ids,\r\n },\r\n })\r\n .subscribe(result => {\r\n if (result) {\r\n notificationService.success(_('common.notify-bulk-update-success'), {\r\n count: selection.length,\r\n entity: mode === 'product' ? 'Products' : 'ProductVariants',\r\n });\r\n clearSelection();\r\n }\r\n });\r\n },\r\n};\r\n","import { NgModule } from '@angular/core';\r\nimport { RouterModule } from '@angular/router';\r\nimport { BulkActionRegistryService, SharedModule } from '@vendure/admin-ui/core';\r\n\r\nimport { catalogRoutes } from './catalog.routes';\r\nimport { ApplyFacetDialogComponent } from './components/apply-facet-dialog/apply-facet-dialog.component';\r\nimport { AssetDetailComponent } from './components/asset-detail/asset-detail.component';\r\nimport { AssetListComponent } from './components/asset-list/asset-list.component';\r\nimport { AssetsComponent } from './components/assets/assets.component';\r\nimport { AssignProductsToChannelDialogComponent } from './components/assign-products-to-channel-dialog/assign-products-to-channel-dialog.component';\r\nimport { AssignToChannelDialogComponent } from './components/assign-to-channel-dialog/assign-to-channel-dialog.component';\r\nimport { BulkAddFacetValuesDialogComponent } from './components/bulk-add-facet-values-dialog/bulk-add-facet-values-dialog.component';\r\nimport { CollectionContentsComponent } from './components/collection-contents/collection-contents.component';\r\nimport { CollectionDetailComponent } from './components/collection-detail/collection-detail.component';\r\nimport {\r\n assignCollectionsToChannelBulkAction,\r\n deleteCollectionsBulkAction,\r\n removeCollectionsFromChannelBulkAction,\r\n} from './components/collection-list/collection-list-bulk-actions';\r\nimport { CollectionListComponent } from './components/collection-list/collection-list.component';\r\nimport { CollectionTreeNodeComponent } from './components/collection-tree/collection-tree-node.component';\r\nimport { CollectionTreeComponent } from './components/collection-tree/collection-tree.component';\r\nimport { ConfirmVariantDeletionDialogComponent } from './components/confirm-variant-deletion-dialog/confirm-variant-deletion-dialog.component';\r\nimport { FacetDetailComponent } from './components/facet-detail/facet-detail.component';\r\nimport {\r\n assignFacetsToChannelBulkAction,\r\n deleteFacetsBulkAction,\r\n removeFacetsFromChannelBulkAction,\r\n} from './components/facet-list/facet-list-bulk-actions';\r\nimport { FacetListComponent } from './components/facet-list/facet-list.component';\r\nimport { GenerateProductVariantsComponent } from './components/generate-product-variants/generate-product-variants.component';\r\nimport { OptionValueInputComponent } from './components/option-value-input/option-value-input.component';\r\nimport { ProductDetailComponent } from './components/product-detail/product-detail.component';\r\nimport {\r\n assignFacetValuesToProductsBulkAction,\r\n assignProductsToChannelBulkAction,\r\n deleteProductsBulkAction,\r\n removeProductsFromChannelBulkAction,\r\n} from './components/product-list/product-list-bulk-actions';\r\nimport { ProductListComponent } from './components/product-list/product-list.component';\r\nimport { ProductOptionsEditorComponent } from './components/product-options-editor/product-options-editor.component';\r\nimport { ProductVariantsEditorComponent } from './components/product-variants-editor/product-variants-editor.component';\r\nimport { ProductVariantsListComponent } from './components/product-variants-list/product-variants-list.component';\r\nimport { ProductVariantsTableComponent } from './components/product-variants-table/product-variants-table.component';\r\nimport { UpdateProductOptionDialogComponent } from './components/update-product-option-dialog/update-product-option-dialog.component';\r\nimport { VariantPriceDetailComponent } from './components/variant-price-detail/variant-price-detail.component';\r\n\r\nconst CATALOG_COMPONENTS = [\r\n ProductListComponent,\r\n ProductDetailComponent,\r\n FacetListComponent,\r\n FacetDetailComponent,\r\n GenerateProductVariantsComponent,\r\n ProductVariantsListComponent,\r\n ApplyFacetDialogComponent,\r\n AssetListComponent,\r\n AssetsComponent,\r\n VariantPriceDetailComponent,\r\n CollectionListComponent,\r\n CollectionDetailComponent,\r\n CollectionTreeComponent,\r\n CollectionTreeNodeComponent,\r\n CollectionContentsComponent,\r\n ProductVariantsTableComponent,\r\n OptionValueInputComponent,\r\n UpdateProductOptionDialogComponent,\r\n ProductVariantsEditorComponent,\r\n AssignProductsToChannelDialogComponent,\r\n AssetDetailComponent,\r\n ConfirmVariantDeletionDialogComponent,\r\n ProductOptionsEditorComponent,\r\n BulkAddFacetValuesDialogComponent,\r\n AssignToChannelDialogComponent,\r\n];\r\n\r\n@NgModule({\r\n imports: [SharedModule, RouterModule.forChild(catalogRoutes)],\r\n exports: [...CATALOG_COMPONENTS],\r\n declarations: [...CATALOG_COMPONENTS],\r\n})\r\nexport class CatalogModule {\r\n constructor(private bulkActionRegistryService: BulkActionRegistryService) {\r\n bulkActionRegistryService.registerBulkAction(assignFacetValuesToProductsBulkAction);\r\n bulkActionRegistryService.registerBulkAction(assignProductsToChannelBulkAction);\r\n bulkActionRegistryService.registerBulkAction(removeProductsFromChannelBulkAction);\r\n bulkActionRegistryService.registerBulkAction(deleteProductsBulkAction);\r\n\r\n bulkActionRegistryService.registerBulkAction(assignFacetsToChannelBulkAction);\r\n bulkActionRegistryService.registerBulkAction(removeFacetsFromChannelBulkAction);\r\n bulkActionRegistryService.registerBulkAction(deleteFacetsBulkAction);\r\n\r\n bulkActionRegistryService.registerBulkAction(assignCollectionsToChannelBulkAction);\r\n bulkActionRegistryService.registerBulkAction(removeCollectionsFromChannelBulkAction);\r\n bulkActionRegistryService.registerBulkAction(deleteCollectionsBulkAction);\r\n }\r\n}\r\n"],"sourceRoot":"webpack:///","file":"430.4469edebdd7335b3.js"}
|
|
1
|
+
{"version":3,"mappings":"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","names":["t","save","c","constructor","n","e","o","a","r","s","super","this","p","customFields","getCustomFieldConfig","ngOnInit","detailForm","name","tags","formBuilder","group","reduce","Object","init","ngOnDestroy","destroy","onAssetChange","get","setValue","markAsDirty","dataService","product","updateAsset","id","value","subscribe","notificationService","success","entity","error","setFormValues","length","setCustomFieldFormValues","rt","selectors","U","setQueryFn","getAssetList","assets","d","m","searchTerm$","_","l","filterByTags$","map","f","options","skip","take","filter","contains","sort","createdAt","tagsOperator","paginationConfig$","itemsPerPage$","currentPage$","totalItems$","pipe","C","itemsPerPage","currentPage","totalItems","destroy$","refresh","allTags$","getTagList","mapStream","items","filesSelected","uploading","createAssets","ue","__typename","message","count","deleteAssets","showModalAndDelete","result","modalService","dialog","title","u","translationVars","body","buttons","type","label","returnValue","b","M","st","selectAssets","oxw","dropListDropped","previewAsset","setAsFeatured","removeAsset","assetsSetter","slice","fromComponent","size","J","concat","featuredAsset","emitChangeEvent","changeDetector","markForCheck","isFeatured","closable","locals","asset","change","emit","previousContainer","data","container","j","$t","contentsCurrentPage$","route","queryParamMap","contentsItemsPerPage$","Y","filterTermControl","valueChanges","q","setContentsPageNumber","mt","filterChanges$","asObservable","Qt","previewUpdatedFilters","inheritFiltersChanges$","inheritFilters","collectionIdChange$","parentIdChange$","refresh$","isLoading","v","Z","T","y","collection","previewCollectionVariants","parentId","filters","mapSingle","L","getCollectionContents","productVariants","k","contents$","contentsTotalItems$","ngOnChanges","next","collectionId","currentValue","updatedFilters","complete","setParam","setContentsItemsPerPage","router","navigate","relativeTo","queryParams","queryParamsHandling","replaceUrl","nt","create","removeFilter","addFilter","toggleLivePreview","updateSlug","slug","description","visible","array","livePreview","localStorageService","getCollectionFilters","single$","allFilters","collectionFilters","inheritFilters$","updatedFilters$","statusChanges","filterRemoved$","$","touched","mapOperationsToInputs","arguments","parentId$","paramMap","entity$","parent","getFilterDefinition","find","code","assetsChanged","values","assetChanges","languageCode$","w","pristine","args","push","control","removeAt","markAsTouched","splice","dirty","I","getUpdatedCollection","snapshot","createCollection","markAsPristine","updateCollection","contentsComponent","canDeactivate","set","trackByFn","JSON","stringify","patchValue","isPrivate","clear","forEach","translatable","updatedFields","customFieldConfig","languageCode","defaultTranslation","assetIds","featuredAssetId","entries","gt","i","Map","children","Xn","hasOwnProperty","expanded","includes","rearrange$","_rearrange$","delete$","_delete$","setCollectionTree","collectionTree","resetMoveList","allMoveListItems","getMoveListItems","calculateAllMoveListItems","ancestorIdPath","has","onDrop","item","Error","index","currentIndex","onMove","onDelete","path","join","Set","B","factory","toggleExpanded","move","selectionManager","moveUp","moveDown","delete","depth","parentName","client","userStatus","permissions","_t","hasUpdatePermission$","hasDeletePermission$","subscription","selectionChanges$","changeDetectorRef","expandAll","previousValue","unsubscribe","split","moveListItems","collectionTreeService","drop","previousIndex","H","pipes","collections","he","expandedIds","rearrange","deleteCollection","ht","closeContents","additiveMode","multiSelect","itemsAreEqual","queryResult","getCollections","refetchOnChannelChange","items$","setCurrentItems","activeCollectionId$","activeCollectionTitle$","availableLanguages$","serverConfigService","getAvailableLanguages","contentLanguage$","uiState","contentLanguage","completed$","toggleExpandAll","onRearrange","moveCollection","findIndex","params","contents","setLanguage","setContentLanguage","ref","refetch","ft","updateValueCode","deleteFacetValue","addFacetValue","updateCode","customValueFields","facet","customValueFieldIsSet","getValuesFormArray","addControl","insert","getUpdatedFacet","createFacet","getAllFacets","updateFacet","getCreatedFacetValues","createFacetValues","getFacet","getUpdatedFacetValues","updateFacetValues","E","deleteFacetValues","controls","S","Wt","Jt","translations","facetId","toString","R","vt","toggleDisplayLimit","deleteFacet","getFacets","facets","So","Q","displayLimit","initialLimit","Ct","cancel","selectValues","ngAfterViewInit","setTimeout","selector","focus","resolveWith","selectedValues","ot","assign","isProductVariantMode","productVariantIds","activeChannelId","settings","getChannels","channels","currentChannel","availableChannels","selectedChannelIdControl","selectChannel","variantsPreview$","jt","getTopVariants","priceFactorControl","price","pricePreview","selectedChannel","assignVariantsToChannel","channelId","priceFactor","channel","assignProductsToChannel","productIds","getProduct","variantList","toPromise","z","lastIndexOf","substr","replace","getTaxCategories","taxCategories","createProductWithVariants","createProduct","groups","createProductOptionGroups","F","addOptionGroupToProduct","productId","optionGroupId","optionGroups","variants","optionValues","optionIds","createProductVariants","createProductOptionGroup","sku","stockOnHand","stock","updateProduct","autoUpdate","productInput","variantsInput","getProductVariants","tn","de","Bt","ce","updateProductVariants","updateProductOption","deleteProductVariant","xi","bi","K","removeOption","updateOption","editName","Oe","provide","useExisting","W","multi","formValue","registerOnChange","onChangeFn","registerOnTouched","onTouchFn","setDisabledState","disabled","writeValue","textArea","nativeElement","locked","cancelBubble","editingIndex","nameInputs","target","edit","option","remove","handleKey","key","addOptionValue","preventDefault","lastSelected","removeLastOption","input","handleBlur","isFocussed","parseInputIntoOptions","add","trim","decls","handleEnter","generateVariants","onFormChange","le","getActiveChannel","currencyCode","activeChannel","addOption","groupNameInputs","variantFormValues","enabled","copyFromDefault","stopPropagation","variantsChange","xt","formArray","buildFormGroupMap","getFeaturedAsset","pendingAssetChanges","optionGroupName","formGroupMap","bt","update","productOption","activeLanguage","customFieldsForm","updateVariantName","codeInputTouched","Zt","getTaxRatesSimple","taxRates","taxRate$","taxCategoryIdChange$","defaultTaxZone","zone","category","grossPrice$","priceChange$","Math","round","taxCategoryId","Tt","editOption","removeFacetValue","selectFacetValue","removeFromChannel","assignToChannel","getGlobalSettings","globalSettings","globalTrackInventory","trackInventory","globalOutOfStockThreshold","outOfStockThreshold","isDefaultChannel","ve","trackById","inventoryIsNotTracked","getTaxCategoryName","getStockOnHandMinValue","getSaleableStockLevel","useGlobalOutOfStockThreshold","stockAllocated","areAllSelected","selectedVariantIds","assetChange","variantId","at","toggleSelectAll","selectionChange","toggleSelectVariant","indexOf","optionName","currentOrPendingFacetValues","pendingFacetValueChanges","facetValues","facetValueIds","isVariantSelected","customOptionFields","getFacetValueIds","At","removeProductFacetValue","selectProductFacetValue","setItemsPerPage","setPage","assignVariantToChannel","removeVariantFromChannel","variantAssetChange","filterInput","navigateToTab","customVariantFields","customOptionGroupFields","autoUpdateVariantNames","product$","ni","Ce","oi","filterOperator","bufferSize","refCount","variants$","te","productVariantMap","taxCategories$","productDetailService","activeTab$","buildVariantFormArray","getProductFormGroup","getFacetValues","in","facetValues$","Xo","ii","productChannels$","channelPriceIncludesTax$","pricesIncludeTax","location","replaceState","createUrlTree","tab","currentChannelIds","channelCode","removeProductsFromChannel","variant","removeVariantsFromChannel","variantAssetsChanged","keys","variantAssetChanges","displayFacetValueModal","variantsToCreateAreValid","createVariantsConfig","every","getUpdatedProduct","console","getUpdatedProductVariants","updateSlugAfterSave","variantFacetValueChanges","priceWithTax","taxCategory","emitEvent","yt","runPendingSearchIndexUpdates","deleteProduct","searchTerm","productSearchInput","setSearchTerm","selectedFacetValueIds$","getAll","setFacetValues","searchProducts","search","term","facetValueOperator","groupByProduct","productVariantId","result$","Ba","getPendingSearchIndexUpdates","pendingSearchIndexUpdates","setQueryParam","page","setFacetValueIds","fvids","rebuildSearchIndex","reindex","info","jobQueueService","addJob","state","Intl","NumberFormat","format","duration","indexedItemCount","time","Pt","optionGroupCustomFields","optionCustomFields","optionGroups$","getOptionGroups","getOptions","invalid","getUpdatedOptionGroup","updateProductOptionGroup","getUpdatedOption","updatedAt","setControl","Ft","confirm","removeOptionGroup","onFormChanged","deleteVariant","Ot","initOptionsAndVariants","formValueChanged","getVariantsToAdd","generatedVariants","existing","getVariantName","addOptionGroup","isNew","optionsChanged","removeOptionGroupFromProduct","deleteProductOption","getVariantPrototype","Le","isDefault","optionsAreEqual","optionsAreSubset","gr","reFetchProduct","checkUniqueSkus","confirmDeletionOfObsoleteVariants","addOptionGroupsToProduct","addNewOptionsToGroups","fetchOptionGroups","createNewProductVariants","deleteObsoleteVariants","getObsoleteVariants","hasOnlyDefaultVariant","productOptionGroupId","addOptionToGroup","getProductOptionGroup","productOptionGroup","_r","getProductVariantsOptions","flat","groupId","toOptionString","It","fileSize","mimeType","width","height","source","preview","focalPoint","getAsset","Mt","breadcrumbs","getCollection","kt","Lt","Vt","it","Ve","component","breadcrumb","resolve","we","Je","De","Ue","Ne","qe","breadcrumbKey","getName","link","Se","Kt","$e","Qe","Ee","addFacetValues","mode","query","ids","products","facetValuesRemoved","mutate","wt","Ye","icon","iconClass","requiresPermission","onClick","injector","selection","hostComponent","clearSelection","deleteCollections","Ge","isVisible","assignCollectionsToChannel","collectionIds","Gt","je","getTranslationVars","removeCollectionsFromChannel","Be","deleteFacets","He","assignFacetsToChannel","facetIds","Re","removeFacetsFromChannel","force","then","removedCount","ze","deleteProducts","Ke","We","Xe","registerBulkAction","St","A"],"sources":["./src/lib/catalog/src/components/asset-detail/asset-detail.component.html","./src/lib/catalog/src/components/asset-detail/asset-detail.component.ts","./src/lib/catalog/src/components/asset-list/asset-list.component.ts","./src/lib/catalog/src/components/asset-list/asset-list.component.html","./src/lib/catalog/src/components/assets/assets.component.html","./src/lib/catalog/src/components/assets/assets.component.ts","./src/lib/catalog/src/components/collection-contents/collection-contents.component.html","./src/lib/catalog/src/components/collection-contents/collection-contents.component.ts","./src/lib/catalog/src/components/collection-detail/collection-detail.component.html","./src/lib/catalog/src/components/collection-detail/collection-detail.component.ts","./src/lib/catalog/src/components/collection-tree/array-to-tree.ts","./src/lib/catalog/src/components/collection-tree/collection-tree.service.ts","./src/lib/catalog/src/components/collection-tree/collection-tree-node.component.html","./src/lib/catalog/src/components/collection-tree/collection-tree-node.component.ts","./src/lib/catalog/src/components/collection-tree/collection-tree.component.html","./src/lib/catalog/src/components/collection-tree/collection-tree.component.ts","./src/lib/catalog/src/components/collection-list/collection-list.component.html","./src/lib/catalog/src/components/collection-list/collection-list.component.ts","./src/lib/catalog/src/components/facet-detail/facet-detail.component.html","./src/lib/catalog/src/components/facet-detail/facet-detail.component.ts","./src/lib/catalog/src/components/facet-list/facet-list.component.html","./src/lib/catalog/src/components/facet-list/facet-list.component.ts","./src/lib/catalog/src/components/apply-facet-dialog/apply-facet-dialog.component.html","./src/lib/catalog/src/components/apply-facet-dialog/apply-facet-dialog.component.ts","./src/lib/catalog/src/components/assign-products-to-channel-dialog/assign-products-to-channel-dialog.component.html","./src/lib/catalog/src/components/assign-products-to-channel-dialog/assign-products-to-channel-dialog.component.ts","./src/lib/catalog/src/providers/product-detail/replace-last.ts","./src/lib/catalog/src/providers/product-detail/product-detail.service.ts","./node_modules/@angular-devkit/build-angular/src/babel/webpack-loader.js","./src/lib/catalog/src/components/option-value-input/option-value-input.component.html","./src/lib/catalog/src/components/option-value-input/option-value-input.component.ts","./src/lib/catalog/src/components/generate-product-variants/generate-product-variants.component.html","./src/lib/catalog/src/components/generate-product-variants/generate-product-variants.component.ts","./src/lib/catalog/src/components/product-variants-table/product-variants-table.component.html","./src/lib/catalog/src/components/product-variants-table/product-variants-table.component.ts","./src/lib/catalog/src/components/update-product-option-dialog/update-product-option-dialog.component.html","./src/lib/catalog/src/components/update-product-option-dialog/update-product-option-dialog.component.ts","./src/lib/catalog/src/components/variant-price-detail/variant-price-detail.component.html","./src/lib/catalog/src/components/variant-price-detail/variant-price-detail.component.ts","./src/lib/catalog/src/components/product-variants-list/product-variants-list.component.html","./src/lib/catalog/src/components/product-variants-list/product-variants-list.component.ts","./src/lib/catalog/src/components/product-detail/product-detail.component.html","./src/lib/catalog/src/components/product-detail/product-detail.component.ts","./src/lib/catalog/src/components/product-list/product-list.component.html","./src/lib/catalog/src/components/product-list/product-list.component.ts","./src/lib/catalog/src/components/product-options-editor/product-options-editor.component.html","./src/lib/catalog/src/components/product-options-editor/product-options-editor.component.ts","./src/lib/catalog/src/components/confirm-variant-deletion-dialog/confirm-variant-deletion-dialog.component.html","./src/lib/catalog/src/components/confirm-variant-deletion-dialog/confirm-variant-deletion-dialog.component.ts","./src/lib/catalog/src/components/product-variants-editor/product-variants-editor.component.html","./src/lib/catalog/src/components/product-variants-editor/product-variants-editor.component.ts","./src/lib/catalog/src/providers/routing/asset-resolver.ts","./src/lib/catalog/src/providers/routing/collection-resolver.ts","./src/lib/catalog/src/providers/routing/facet-resolver.ts","./src/lib/catalog/src/providers/routing/product-resolver.ts","./src/lib/catalog/src/providers/routing/product-variants-resolver.ts","./src/lib/catalog/src/catalog.routes.ts","./src/lib/catalog/src/components/assign-to-channel-dialog/assign-to-channel-dialog.component.html","./src/lib/catalog/src/components/assign-to-channel-dialog/assign-to-channel-dialog.component.ts","./src/lib/catalog/src/components/bulk-add-facet-values-dialog/bulk-add-facet-values-dialog.graphql.ts","./src/lib/catalog/src/components/bulk-add-facet-values-dialog/bulk-add-facet-values-dialog.component.html","./src/lib/catalog/src/components/bulk-add-facet-values-dialog/bulk-add-facet-values-dialog.component.ts","./src/lib/catalog/src/components/collection-list/collection-list-bulk-actions.ts","./src/lib/catalog/src/components/facet-list/facet-list-bulk-actions.ts","./src/lib/catalog/src/components/product-list/product-list-bulk-actions.ts","./src/lib/catalog/src/catalog.module.ts"],"sourcesContent":["<vdr-action-bar>\r\n <vdr-ab-left>\r\n <vdr-entity-info [entity]=\"entity$ | async\"></vdr-entity-info>\r\n </vdr-ab-left>\r\n\r\n <vdr-ab-right>\r\n <vdr-action-bar-items locationId=\"asset-detail\"></vdr-action-bar-items>\r\n <button\r\n *vdrIfPermissions=\"['UpdateCatalog', 'UpdateAsset']\"\r\n class=\"btn btn-primary\"\r\n (click)=\"save()\"\r\n [disabled]=\"detailForm.invalid || detailForm.pristine\"\r\n >\r\n {{ 'common.update' | translate }}\r\n </button>\r\n </vdr-ab-right>\r\n</vdr-action-bar>\r\n<vdr-asset-preview\r\n [asset]=\"entity$ | async\"\r\n [editable]=\"true\"\r\n [customFields]=\"customFields\"\r\n [customFieldsForm]=\"detailForm.get('customFields')\"\r\n (assetChange)=\"onAssetChange($event)\"\r\n></vdr-asset-preview>\r\n","import { ChangeDetectionStrategy, Component, OnDestroy, OnInit } from '@angular/core';\r\nimport { FormBuilder, FormControl, FormGroup } from '@angular/forms';\r\nimport { ActivatedRoute, Router } from '@angular/router';\r\nimport { marker as _ } from '@biesbjerg/ngx-translate-extract-marker';\r\nimport {\r\n Asset,\r\n BaseDetailComponent,\r\n CustomFieldConfig,\r\n DataService,\r\n GetAssetQuery,\r\n LanguageCode,\r\n NotificationService,\r\n ServerConfigService,\r\n} from '@vendure/admin-ui/core';\r\n\r\n@Component({\r\n selector: 'vdr-asset-detail',\r\n templateUrl: './asset-detail.component.html',\r\n styleUrls: ['./asset-detail.component.scss'],\r\n changeDetection: ChangeDetectionStrategy.OnPush,\r\n})\r\nexport class AssetDetailComponent\r\n extends BaseDetailComponent<NonNullable<GetAssetQuery['asset']>>\r\n implements OnInit, OnDestroy\r\n{\r\n detailForm = new FormGroup({});\r\n customFields: CustomFieldConfig[];\r\n\r\n constructor(\r\n router: Router,\r\n route: ActivatedRoute,\r\n serverConfigService: ServerConfigService,\r\n private notificationService: NotificationService,\r\n protected dataService: DataService,\r\n private formBuilder: FormBuilder,\r\n ) {\r\n super(route, router, serverConfigService, dataService);\r\n this.customFields = this.getCustomFieldConfig('Asset');\r\n }\r\n\r\n ngOnInit() {\r\n this.detailForm = new FormGroup({\r\n name: new FormControl(''),\r\n tags: new FormControl([]),\r\n customFields: this.formBuilder.group(\r\n this.customFields.reduce((hash, field) => ({ ...hash, [field.name]: '' }), {}),\r\n ),\r\n });\r\n this.init();\r\n }\r\n\r\n ngOnDestroy() {\r\n this.destroy();\r\n }\r\n\r\n onAssetChange(event: { id: string; name: string; tags: string[] }) {\r\n this.detailForm.get('name')?.setValue(event.name);\r\n this.detailForm.get('tags')?.setValue(event.tags);\r\n this.detailForm.markAsDirty();\r\n }\r\n\r\n save() {\r\n this.dataService.product\r\n .updateAsset({\r\n id: this.id,\r\n name: this.detailForm.value.name,\r\n tags: this.detailForm.value.tags,\r\n customFields: this.detailForm.value.customFields,\r\n })\r\n .subscribe(\r\n () => {\r\n this.notificationService.success(_('common.notify-update-success'), { entity: 'Asset' });\r\n },\r\n err => {\r\n this.notificationService.error(_('common.notify-update-error'), {\r\n entity: 'Asset',\r\n });\r\n },\r\n );\r\n }\r\n\r\n protected setFormValues(entity: NonNullable<GetAssetQuery['asset']>, languageCode: LanguageCode): void {\r\n this.detailForm.get('name')?.setValue(entity.name);\r\n this.detailForm.get('tags')?.setValue(entity.tags);\r\n if (this.customFields.length) {\r\n this.setCustomFieldFormValues(this.customFields, this.detailForm.get(['customFields']), entity);\r\n }\r\n }\r\n}\r\n","import { Component, OnInit } from '@angular/core';\r\nimport { ActivatedRoute, Router } from '@angular/router';\r\nimport { marker as _ } from '@biesbjerg/ngx-translate-extract-marker';\r\nimport {\r\n Asset,\r\n BaseListComponent,\r\n DataService,\r\n DeletionResult,\r\n GetAssetListQuery,\r\n GetAssetListQueryVariables,\r\n ItemOf,\r\n LogicalOperator,\r\n ModalService,\r\n NotificationService,\r\n SortOrder,\r\n TagFragment,\r\n} from '@vendure/admin-ui/core';\r\nimport { PaginationInstance } from 'ngx-pagination';\r\nimport { BehaviorSubject, combineLatest, EMPTY, Observable } from 'rxjs';\r\nimport { debounceTime, finalize, map, switchMap, takeUntil } from 'rxjs/operators';\r\n\r\n@Component({\r\n selector: 'vdr-asset-list',\r\n templateUrl: './asset-list.component.html',\r\n styleUrls: ['./asset-list.component.scss'],\r\n})\r\nexport class AssetListComponent\r\n extends BaseListComponent<\r\n GetAssetListQuery,\r\n ItemOf<GetAssetListQuery, 'assets'>,\r\n GetAssetListQueryVariables\r\n >\r\n implements OnInit\r\n{\r\n searchTerm$ = new BehaviorSubject<string | undefined>(undefined);\r\n filterByTags$ = new BehaviorSubject<TagFragment[] | undefined>(undefined);\r\n uploading = false;\r\n allTags$: Observable<TagFragment[]>;\r\n paginationConfig$: Observable<PaginationInstance>;\r\n\r\n constructor(\r\n private notificationService: NotificationService,\r\n private modalService: ModalService,\r\n private dataService: DataService,\r\n router: Router,\r\n route: ActivatedRoute,\r\n ) {\r\n super(router, route);\r\n super.setQueryFn(\r\n (...args: any[]) => this.dataService.product.getAssetList(...args),\r\n data => data.assets,\r\n (skip, take) => {\r\n const searchTerm = this.searchTerm$.value;\r\n const tags = this.filterByTags$.value?.map(t => t.value);\r\n return {\r\n options: {\r\n skip,\r\n take,\r\n ...(searchTerm\r\n ? {\r\n filter: {\r\n name: { contains: searchTerm },\r\n },\r\n }\r\n : {}),\r\n sort: {\r\n createdAt: SortOrder.DESC,\r\n },\r\n tags,\r\n tagsOperator: LogicalOperator.AND,\r\n },\r\n };\r\n },\r\n { take: 25, skip: 0 },\r\n );\r\n }\r\n\r\n ngOnInit() {\r\n super.ngOnInit();\r\n this.paginationConfig$ = combineLatest(this.itemsPerPage$, this.currentPage$, this.totalItems$).pipe(\r\n map(([itemsPerPage, currentPage, totalItems]) => ({ itemsPerPage, currentPage, totalItems })),\r\n );\r\n this.searchTerm$.pipe(debounceTime(250), takeUntil(this.destroy$)).subscribe(() => this.refresh());\r\n\r\n this.filterByTags$.pipe(takeUntil(this.destroy$)).subscribe(() => this.refresh());\r\n this.allTags$ = this.dataService.product.getTagList().mapStream(data => data.tags.items);\r\n }\r\n\r\n filesSelected(files: File[]) {\r\n if (files.length) {\r\n this.uploading = true;\r\n this.dataService.product\r\n .createAssets(files)\r\n .pipe(finalize(() => (this.uploading = false)))\r\n .subscribe(({ createAssets }) => {\r\n let successCount = 0;\r\n for (const result of createAssets) {\r\n switch (result.__typename) {\r\n case 'Asset':\r\n successCount++;\r\n break;\r\n case 'MimeTypeError':\r\n this.notificationService.error(result.message);\r\n break;\r\n }\r\n }\r\n if (0 < successCount) {\r\n super.refresh();\r\n this.notificationService.success(_('asset.notify-create-assets-success'), {\r\n count: successCount,\r\n });\r\n }\r\n });\r\n }\r\n }\r\n\r\n deleteAssets(assets: Asset[]) {\r\n this.showModalAndDelete(assets.map(a => a.id))\r\n .pipe(\r\n switchMap(response => {\r\n if (response.result === DeletionResult.DELETED) {\r\n return [true];\r\n } else {\r\n return this.showModalAndDelete(\r\n assets.map(a => a.id),\r\n response.message || '',\r\n ).pipe(map(r => r.result === DeletionResult.DELETED));\r\n }\r\n }),\r\n )\r\n .subscribe(\r\n () => {\r\n this.notificationService.success(_('common.notify-delete-success'), {\r\n entity: 'Assets',\r\n });\r\n this.refresh();\r\n },\r\n err => {\r\n this.notificationService.error(_('common.notify-delete-error'), {\r\n entity: 'Assets',\r\n });\r\n },\r\n );\r\n }\r\n\r\n private showModalAndDelete(assetIds: string[], message?: string) {\r\n return this.modalService\r\n .dialog({\r\n title: _('catalog.confirm-delete-assets'),\r\n translationVars: {\r\n count: assetIds.length,\r\n },\r\n body: message,\r\n buttons: [\r\n { type: 'secondary', label: _('common.cancel') },\r\n { type: 'danger', label: _('common.delete'), returnValue: true },\r\n ],\r\n })\r\n .pipe(\r\n switchMap(res => (res ? this.dataService.product.deleteAssets(assetIds, !!message) : EMPTY)),\r\n map(res => res.deleteAssets),\r\n );\r\n }\r\n}\r\n","<vdr-action-bar>\r\n <vdr-ab-left [grow]=\"true\">\r\n <vdr-asset-search-input\r\n class=\"pr4 mt1\"\r\n [tags]=\"allTags$ | async\"\r\n (searchTermChange)=\"searchTerm$.next($event)\"\r\n (tagsChange)=\"filterByTags$.next($event)\"\r\n ></vdr-asset-search-input>\r\n </vdr-ab-left>\r\n <vdr-ab-right>\r\n <vdr-action-bar-items locationId=\"asset-list\"></vdr-action-bar-items>\r\n <vdr-asset-file-input\r\n (selectFiles)=\"filesSelected($event)\"\r\n [uploading]=\"uploading\"\r\n dropZoneTarget=\".content-area\"\r\n ></vdr-asset-file-input>\r\n </vdr-ab-right>\r\n</vdr-action-bar>\r\n\r\n<vdr-asset-gallery\r\n [assets]=\"(items$ | async)! | paginate: (paginationConfig$ | async) || {}\"\r\n [multiSelect]=\"true\"\r\n [canDelete]=\"['DeleteCatalog', 'DeleteAsset'] | hasPermission\"\r\n (deleteAssets)=\"deleteAssets($event)\"\r\n></vdr-asset-gallery>\r\n\r\n<div class=\"paging-controls\">\r\n <vdr-items-per-page-controls\r\n [itemsPerPage]=\"itemsPerPage$ | async\"\r\n (itemsPerPageChange)=\"setItemsPerPage($event)\"\r\n ></vdr-items-per-page-controls>\r\n\r\n <vdr-pagination-controls\r\n [currentPage]=\"currentPage$ | async\"\r\n [itemsPerPage]=\"itemsPerPage$ | async\"\r\n [totalItems]=\"totalItems$ | async\"\r\n (pageChange)=\"setPageNumber($event)\"\r\n ></vdr-pagination-controls>\r\n</div>\r\n","<div class=\"card\" *ngIf=\"!compact; else compactView\">\r\n <div class=\"card-img\">\r\n <div class=\"featured-asset\">\r\n <img\r\n *ngIf=\"featuredAsset\"\r\n [src]=\"featuredAsset | assetPreview:'small'\"\r\n (click)=\"previewAsset(featuredAsset)\"\r\n />\r\n <div class=\"placeholder\" *ngIf=\"!featuredAsset\" (click)=\"selectAssets()\">\r\n <clr-icon shape=\"image\" size=\"128\"></clr-icon>\r\n <div>{{ 'catalog.no-featured-asset' | translate }}</div>\r\n </div>\r\n </div>\r\n </div>\r\n <div class=\"card-block\"><ng-container *ngTemplateOutlet=\"assetList\"></ng-container></div>\r\n <div class=\"card-footer\" *vdrIfPermissions=\"updatePermissions\">\r\n <button class=\"btn\" (click)=\"selectAssets()\">\r\n <clr-icon shape=\"attachment\"></clr-icon>\r\n {{ 'asset.add-asset' | translate }}\r\n </button>\r\n </div>\r\n</div>\r\n\r\n<ng-template #compactView>\r\n <div class=\"featured-asset compact\">\r\n <img\r\n *ngIf=\"featuredAsset\"\r\n [src]=\"featuredAsset | assetPreview:'thumb'\"\r\n (click)=\"previewAsset(featuredAsset)\"\r\n />\r\n\r\n <div class=\"placeholder\" *ngIf=\"!featuredAsset\" (click)=\"selectAssets()\"><clr-icon shape=\"image\" size=\"150\"></clr-icon></div>\r\n </div>\r\n <ng-container *ngTemplateOutlet=\"assetList\"></ng-container>\r\n <button\r\n *vdrIfPermissions=\"updatePermissions\"\r\n class=\"compact-select btn btn-icon btn-sm btn-block\"\r\n [title]=\"'asset.add-asset' | translate\"\r\n (click)=\"selectAssets()\"\r\n >\r\n <clr-icon shape=\"attachment\"></clr-icon>\r\n {{ 'asset.add-asset' | translate }}\r\n </button>\r\n</ng-template>\r\n\r\n<ng-template #assetList>\r\n <div class=\"all-assets\" [class.compact]=\"compact\" cdkDropListGroup>\r\n <div\r\n *ngFor=\"let asset of assets; let index = index\"\r\n class=\"drop-list\"\r\n cdkDropList\r\n cdkDropListOrientation=\"horizontal\"\r\n [cdkDropListData]=\"index\"\r\n [cdkDropListDisabled]=\"!(updatePermissions | hasPermission)\"\r\n (cdkDropListDropped)=\"dropListDropped($event)\"\r\n >\r\n <vdr-dropdown cdkDrag>\r\n <div\r\n class=\"asset-thumb\"\r\n vdrDropdownTrigger\r\n [class.featured]=\"isFeatured(asset)\"\r\n [title]=\"\"\r\n tabindex=\"0\"\r\n >\r\n <img [src]=\"asset | assetPreview:'tiny'\" />\r\n </div>\r\n <vdr-dropdown-menu vdrPosition=\"bottom-right\">\r\n <button type=\"button\" vdrDropdownItem (click)=\"previewAsset(asset)\">\r\n {{ 'asset.preview' | translate }}\r\n </button>\r\n <button\r\n type=\"button\"\r\n [disabled]=\"isFeatured(asset) || !(updatePermissions | hasPermission)\"\r\n vdrDropdownItem\r\n (click)=\"setAsFeatured(asset)\"\r\n >\r\n {{ 'asset.set-as-featured-asset' | translate }}\r\n </button>\r\n <div class=\"dropdown-divider\"></div>\r\n <button\r\n type=\"button\"\r\n class=\"remove-asset\"\r\n vdrDropdownItem\r\n [disabled]=\"!(updatePermissions | hasPermission)\"\r\n (click)=\"removeAsset(asset)\"\r\n >\r\n {{ 'asset.remove-asset' | translate }}\r\n </button>\r\n </vdr-dropdown-menu>\r\n </vdr-dropdown>\r\n </div>\r\n </div>\r\n</ng-template>\r\n","import { CdkDragDrop, moveItemInArray } from '@angular/cdk/drag-drop';\r\nimport {\r\n ChangeDetectionStrategy,\r\n ChangeDetectorRef,\r\n Component,\r\n EventEmitter,\r\n HostBinding,\r\n Input,\r\n Output,\r\n} from '@angular/core';\r\nimport {\r\n Asset,\r\n AssetPickerDialogComponent,\r\n AssetPreviewDialogComponent,\r\n ModalService,\r\n Permission,\r\n} from '@vendure/admin-ui/core';\r\nimport { unique } from '@vendure/common/lib/unique';\r\n\r\nexport interface AssetChange {\r\n assets: Asset[];\r\n featuredAsset: Asset | undefined;\r\n}\r\n\r\n/**\r\n * A component which displays the Assets, and allows assets to be removed and\r\n * added, and for the featured asset to be set.\r\n *\r\n * Note: rather complex code for drag drop is due to a limitation of the default CDK implementation\r\n * which is addressed by a work-around from here: https://github.com/angular/components/issues/13372#issuecomment-483998378\r\n */\r\n@Component({\r\n selector: 'vdr-assets',\r\n templateUrl: './assets.component.html',\r\n styleUrls: ['./assets.component.scss'],\r\n changeDetection: ChangeDetectionStrategy.OnPush,\r\n})\r\nexport class AssetsComponent {\r\n @Input('assets') set assetsSetter(val: Asset[]) {\r\n // create a new non-readonly array of assets\r\n this.assets = (val || []).slice();\r\n }\r\n\r\n @Input() featuredAsset: Asset | undefined;\r\n @HostBinding('class.compact')\r\n @Input()\r\n compact = false;\r\n @Output() change = new EventEmitter<AssetChange>();\r\n\r\n public assets: Asset[] = [];\r\n\r\n @Input()\r\n updatePermissions: string | string[] | Permission | Permission[];\r\n\r\n constructor(private modalService: ModalService, private changeDetector: ChangeDetectorRef) {}\r\n\r\n selectAssets() {\r\n this.modalService\r\n .fromComponent(AssetPickerDialogComponent, {\r\n size: 'xl',\r\n })\r\n .subscribe(result => {\r\n if (result && result.length) {\r\n this.assets = unique(this.assets.concat(result), 'id');\r\n if (!this.featuredAsset) {\r\n this.featuredAsset = result[0];\r\n }\r\n this.emitChangeEvent(this.assets, this.featuredAsset);\r\n this.changeDetector.markForCheck();\r\n }\r\n });\r\n }\r\n\r\n setAsFeatured(asset: Asset) {\r\n this.featuredAsset = asset;\r\n this.emitChangeEvent(this.assets, asset);\r\n }\r\n\r\n isFeatured(asset: Asset): boolean {\r\n return !!this.featuredAsset && this.featuredAsset.id === asset.id;\r\n }\r\n\r\n previewAsset(asset: Asset) {\r\n this.modalService\r\n .fromComponent(AssetPreviewDialogComponent, {\r\n size: 'xl',\r\n closable: true,\r\n locals: { asset },\r\n })\r\n .subscribe();\r\n }\r\n\r\n removeAsset(asset: Asset) {\r\n this.assets = this.assets.filter(a => a.id !== asset.id);\r\n if (this.featuredAsset && this.featuredAsset.id === asset.id) {\r\n this.featuredAsset = this.assets.length > 0 ? this.assets[0] : undefined;\r\n }\r\n this.emitChangeEvent(this.assets, this.featuredAsset);\r\n }\r\n\r\n private emitChangeEvent(assets: Asset[], featuredAsset: Asset | undefined) {\r\n this.change.emit({\r\n assets,\r\n featuredAsset,\r\n });\r\n }\r\n\r\n dropListDropped(event: CdkDragDrop<number>) {\r\n moveItemInArray(this.assets, event.previousContainer.data, event.container.data);\r\n this.emitChangeEvent(this.assets, this.featuredAsset);\r\n }\r\n}\r\n","<div class=\"contents-header\">\r\n <div class=\"header-title-row\">\r\n <ng-container\r\n *ngTemplateOutlet=\"headerTemplate; context: { $implicit: contentsTotalItems$ | async }\"\r\n ></ng-container>\r\n </div>\r\n <input\r\n type=\"text\"\r\n [placeholder]=\"'catalog.filter-by-name' | translate\"\r\n [formControl]=\"filterTermControl\"\r\n />\r\n</div>\r\n<div class=\"table-wrapper\">\r\n <div class=\"progress loop\" [class.visible]=\"isLoading\"></div>\r\n <vdr-data-table\r\n [class.loading]=\"isLoading\"\r\n [items]=\"contents$ | async\"\r\n [itemsPerPage]=\"contentsItemsPerPage$ | async\"\r\n [totalItems]=\"contentsTotalItems$ | async\"\r\n [currentPage]=\"contentsCurrentPage$ | async\"\r\n (pageChange)=\"setContentsPageNumber($event)\"\r\n (itemsPerPageChange)=\"setContentsItemsPerPage($event)\"\r\n >\r\n <ng-template let-variant=\"item\">\r\n <td class=\"left align-middle\">{{ variant.name }}</td>\r\n <td class=\"left align-middle\"><small class=\"sku\">{{ variant.sku }}</small></td>\r\n <td class=\"right align-middle\">\r\n <vdr-table-row-action\r\n iconShape=\"edit\"\r\n [label]=\"'common.edit' | translate\"\r\n [linkTo]=\"['/catalog/products', variant.productId, { tab: 'variants' }]\"\r\n ></vdr-table-row-action>\r\n </td>\r\n </ng-template>\r\n </vdr-data-table>\r\n</div>\r\n","import {\r\n ChangeDetectionStrategy,\r\n Component,\r\n ContentChild,\r\n Input,\r\n OnChanges,\r\n OnDestroy,\r\n OnInit,\r\n SimpleChanges,\r\n TemplateRef,\r\n} from '@angular/core';\r\nimport { FormControl } from '@angular/forms';\r\nimport { ActivatedRoute, Router } from '@angular/router';\r\nimport {\r\n CollectionFilterParameter,\r\n ConfigurableOperationInput,\r\n DataService,\r\n GetCollectionContentsQuery,\r\n} from '@vendure/admin-ui/core';\r\nimport { BehaviorSubject, combineLatest, Observable, of, Subject } from 'rxjs';\r\nimport {\r\n catchError,\r\n debounceTime,\r\n distinctUntilChanged,\r\n filter,\r\n finalize,\r\n map,\r\n startWith,\r\n switchMap,\r\n takeUntil,\r\n tap,\r\n} from 'rxjs/operators';\r\n\r\n@Component({\r\n selector: 'vdr-collection-contents',\r\n templateUrl: './collection-contents.component.html',\r\n styleUrls: ['./collection-contents.component.scss'],\r\n changeDetection: ChangeDetectionStrategy.OnPush,\r\n})\r\nexport class CollectionContentsComponent implements OnInit, OnChanges, OnDestroy {\r\n @Input() collectionId: string;\r\n @Input() parentId: string;\r\n @Input() inheritFilters: boolean;\r\n @Input() updatedFilters: ConfigurableOperationInput[] | undefined;\r\n @Input() previewUpdatedFilters = false;\r\n @ContentChild(TemplateRef, { static: true }) headerTemplate: TemplateRef<any>;\r\n\r\n contents$: Observable<NonNullable<GetCollectionContentsQuery['collection']>['productVariants']['items']>;\r\n contentsTotalItems$: Observable<number>;\r\n contentsItemsPerPage$: Observable<number>;\r\n contentsCurrentPage$: Observable<number>;\r\n filterTermControl = new FormControl('');\r\n isLoading = false;\r\n private collectionIdChange$ = new BehaviorSubject<string>('');\r\n private parentIdChange$ = new BehaviorSubject<string>('');\r\n private filterChanges$ = new BehaviorSubject<ConfigurableOperationInput[]>([]);\r\n private inheritFiltersChanges$ = new BehaviorSubject<boolean>(true);\r\n private refresh$ = new BehaviorSubject<boolean>(true);\r\n private destroy$ = new Subject<void>();\r\n\r\n constructor(private route: ActivatedRoute, private router: Router, private dataService: DataService) {}\r\n\r\n ngOnInit() {\r\n this.contentsCurrentPage$ = this.route.queryParamMap.pipe(\r\n map(qpm => qpm.get('contentsPage')),\r\n map(page => (!page ? 1 : +page)),\r\n startWith(1),\r\n distinctUntilChanged(),\r\n );\r\n\r\n this.contentsItemsPerPage$ = this.route.queryParamMap.pipe(\r\n map(qpm => qpm.get('contentsPerPage')),\r\n map(perPage => (!perPage ? 10 : +perPage)),\r\n startWith(10),\r\n distinctUntilChanged(),\r\n );\r\n\r\n const filterTerm$ = this.filterTermControl.valueChanges.pipe(\r\n debounceTime(250),\r\n tap(() => this.setContentsPageNumber(1)),\r\n startWith(''),\r\n );\r\n\r\n const filterChanges$ = this.filterChanges$.asObservable().pipe(\r\n filter(() => this.previewUpdatedFilters),\r\n tap(() => this.setContentsPageNumber(1)),\r\n startWith([]),\r\n );\r\n\r\n const inheritFiltersChanges$ = this.inheritFiltersChanges$.asObservable().pipe(\r\n filter(() => this.inheritFilters != null),\r\n distinctUntilChanged(),\r\n tap(() => this.setContentsPageNumber(1)),\r\n startWith(true),\r\n );\r\n\r\n const fetchUpdate$ = combineLatest(\r\n this.collectionIdChange$,\r\n this.parentIdChange$,\r\n this.contentsCurrentPage$,\r\n this.contentsItemsPerPage$,\r\n filterTerm$,\r\n filterChanges$,\r\n inheritFiltersChanges$,\r\n this.refresh$,\r\n );\r\n\r\n const collection$ = fetchUpdate$.pipe(\r\n takeUntil(this.destroy$),\r\n tap(() => (this.isLoading = true)),\r\n debounceTime(50),\r\n switchMap(([id, parentId, currentPage, itemsPerPage, filterTerm, filters, inheritFilters]) => {\r\n const take = itemsPerPage;\r\n const skip = (currentPage - 1) * itemsPerPage;\r\n if (filters.length && this.previewUpdatedFilters) {\r\n const filterClause = filterTerm\r\n ? ({ name: { contains: filterTerm } } as CollectionFilterParameter)\r\n : undefined;\r\n return this.dataService.collection\r\n .previewCollectionVariants(\r\n {\r\n parentId,\r\n filters,\r\n inheritFilters,\r\n },\r\n {\r\n take,\r\n skip,\r\n filter: filterClause,\r\n },\r\n )\r\n .mapSingle(data => data.previewCollectionVariants)\r\n .pipe(catchError(() => of({ items: [], totalItems: 0 })));\r\n } else if (id) {\r\n return this.dataService.collection\r\n .getCollectionContents(id, take, skip, filterTerm)\r\n .mapSingle(data => data.collection?.productVariants);\r\n } else {\r\n return of(null);\r\n }\r\n }),\r\n tap(() => (this.isLoading = false)),\r\n finalize(() => (this.isLoading = false)),\r\n );\r\n\r\n this.contents$ = collection$.pipe(map(result => (result ? result.items : [])));\r\n this.contentsTotalItems$ = collection$.pipe(map(result => (result ? result.totalItems : 0)));\r\n }\r\n\r\n ngOnChanges(changes: SimpleChanges): void {\r\n if ('collectionId' in changes) {\r\n this.collectionIdChange$.next(changes.collectionId.currentValue);\r\n }\r\n if ('parentId' in changes) {\r\n this.parentIdChange$.next(changes.parentId.currentValue);\r\n }\r\n if ('inheritFilters' in changes) {\r\n this.inheritFiltersChanges$.next(changes.inheritFilters.currentValue);\r\n }\r\n if ('updatedFilters' in changes) {\r\n if (this.updatedFilters) {\r\n this.filterChanges$.next(this.updatedFilters);\r\n }\r\n }\r\n }\r\n\r\n ngOnDestroy() {\r\n this.destroy$.next();\r\n this.destroy$.complete();\r\n }\r\n\r\n setContentsPageNumber(page: number) {\r\n this.setParam('contentsPage', page);\r\n }\r\n\r\n setContentsItemsPerPage(perPage: number) {\r\n this.setParam('contentsPerPage', perPage);\r\n }\r\n\r\n refresh() {\r\n this.refresh$.next(true);\r\n }\r\n\r\n private setParam(key: string, value: any) {\r\n this.router.navigate(['./'], {\r\n relativeTo: this.route,\r\n queryParams: {\r\n [key]: value,\r\n },\r\n queryParamsHandling: 'merge',\r\n replaceUrl: true,\r\n });\r\n }\r\n}\r\n","<vdr-action-bar>\r\n <vdr-ab-left>\r\n <vdr-entity-info [entity]=\"entity$ | async\"></vdr-entity-info>\r\n <vdr-language-selector\r\n [disabled]=\"isNew$ | async\"\r\n [availableLanguageCodes]=\"availableLanguages$ | async\"\r\n [currentLanguageCode]=\"languageCode$ | async\"\r\n (languageCodeChange)=\"setLanguage($event)\"\r\n ></vdr-language-selector>\r\n </vdr-ab-left>\r\n\r\n <vdr-ab-right>\r\n <vdr-action-bar-items locationId=\"collection-detail\"></vdr-action-bar-items>\r\n <button\r\n class=\"btn btn-primary\"\r\n *ngIf=\"isNew$ | async; else updateButton\"\r\n (click)=\"create()\"\r\n [disabled]=\"detailForm.invalid || detailForm.pristine\"\r\n >\r\n {{ 'common.create' | translate }}\r\n </button>\r\n <ng-template #updateButton>\r\n <button\r\n *vdrIfPermissions=\"updatePermission\"\r\n class=\"btn btn-primary\"\r\n (click)=\"save()\"\r\n [disabled]=\"(detailForm.invalid || detailForm.pristine) && !assetsChanged()\"\r\n >\r\n {{ 'common.update' | translate }}\r\n </button>\r\n </ng-template>\r\n </vdr-ab-right>\r\n</vdr-action-bar>\r\n<form class=\"form\" [formGroup]=\"detailForm\" *ngIf=\"entity$ | async as collection\">\r\n\r\n <nav role=\"navigation\">\r\n <ul class=\"collection-breadcrumbs\">\r\n <li *ngFor=\"let breadcrumb of collection.breadcrumbs; let isFirst = first; let isLast = last\">\r\n <a [routerLink]=\"['/catalog/collections']\" *ngIf=\"isFirst\">{{ 'catalog.root-collection' | translate }}</a>\r\n <a [routerLink]=\"['/catalog/collections', breadcrumb.id]\" *ngIf=\"!isFirst && !isLast\">{{ breadcrumb.name | translate }}</a>\r\n <ng-container *ngIf=\"isLast\">{{ breadcrumb.name | translate }}</ng-container>\r\n </li>\r\n </ul>\r\n </nav>\r\n <div class=\"clr-row\">\r\n <div class=\"clr-col\">\r\n <vdr-form-field [label]=\"'catalog.visibility' | translate\" for=\"visibility\">\r\n <clr-toggle-wrapper>\r\n <input\r\n type=\"checkbox\"\r\n clrToggle\r\n formControlName=\"visible\"\r\n id=\"visibility\"\r\n [vdrDisabled]=\"!(updatePermission | hasPermission)\"\r\n />\r\n <label class=\"visible-toggle\">\r\n <ng-container *ngIf=\"detailForm.value.visible; else private\">{{\r\n 'catalog.public' | translate\r\n }}</ng-container>\r\n <ng-template #private>{{ 'catalog.private' | translate }}</ng-template>\r\n </label>\r\n </clr-toggle-wrapper>\r\n </vdr-form-field>\r\n <vdr-form-field [label]=\"'common.name' | translate\" for=\"name\">\r\n <input\r\n id=\"name\"\r\n type=\"text\"\r\n formControlName=\"name\"\r\n [readonly]=\"!(updatePermission | hasPermission)\"\r\n (input)=\"updateSlug($event.target.value)\"\r\n />\r\n </vdr-form-field>\r\n <vdr-form-field\r\n [label]=\"'catalog.slug' | translate\"\r\n for=\"slug\"\r\n [errors]=\"{ pattern: ('catalog.slug-pattern-error' | translate) }\"\r\n >\r\n <input\r\n id=\"slug\"\r\n type=\"text\"\r\n formControlName=\"slug\"\r\n [readonly]=\"!(updatePermission | hasPermission)\"\r\n />\r\n </vdr-form-field>\r\n <vdr-rich-text-editor\r\n formControlName=\"description\"\r\n [readonly]=\"!(updatePermission | hasPermission)\"\r\n [label]=\"'common.description' | translate\"\r\n ></vdr-rich-text-editor>\r\n\r\n <section formGroupName=\"customFields\" *ngIf=\"customFields.length\">\r\n <label>{{ 'common.custom-fields' | translate }}</label>\r\n <vdr-tabbed-custom-fields\r\n entityName=\"Collection\"\r\n [customFields]=\"customFields\"\r\n [customFieldsFormGroup]=\"detailForm.get(['customFields'])\"\r\n [readonly]=\"!(updatePermission | hasPermission)\"\r\n ></vdr-tabbed-custom-fields>\r\n </section>\r\n <vdr-custom-detail-component-host\r\n locationId=\"collection-detail\"\r\n [entity$]=\"entity$\"\r\n [detailForm]=\"detailForm\"\r\n ></vdr-custom-detail-component-host>\r\n </div>\r\n <div class=\"clr-col-md-auto\">\r\n <vdr-assets\r\n [assets]=\"collection.assets\"\r\n [featuredAsset]=\"collection.featuredAsset\"\r\n [updatePermissions]=\"updatePermission\"\r\n (change)=\"assetChanges = $event\"\r\n ></vdr-assets>\r\n </div>\r\n </div>\r\n <div class=\"clr-row\">\r\n <div class=\"clr-col\">\r\n <label>{{ 'catalog.filters' | translate }}</label>\r\n <vdr-form-field [label]=\"'catalog.filter-inheritance' | translate\" for=\"inheritFilters\">\r\n <clr-toggle-wrapper>\r\n <input\r\n type=\"checkbox\"\r\n clrToggle\r\n formControlName=\"inheritFilters\"\r\n id=\"inheritFilters\"\r\n [vdrDisabled]=\"!(updatePermission | hasPermission)\"\r\n />\r\n <label class=\"visible-toggle\">\r\n <ng-container *ngIf=\"detailForm.value.inheritFilters; else noInherit\">{{\r\n 'catalog.inherit-filters-from-parent' | translate\r\n }}</ng-container>\r\n <ng-template #noInherit>{{\r\n 'catalog.do-not-inherit-filters' | translate\r\n }}</ng-template>\r\n </label>\r\n </clr-toggle-wrapper>\r\n </vdr-form-field>\r\n <div formArrayName=\"filters\">\r\n <ng-container *ngFor=\"let filter of filters; index as i; trackBy:trackByFn\">\r\n <vdr-configurable-input\r\n (remove)=\"removeFilter(i)\"\r\n [position]=\"i\"\r\n [operation]=\"filter\"\r\n [operationDefinition]=\"getFilterDefinition(filter)\"\r\n [formControlName]=\"i\"\r\n [readonly]=\"!(updatePermission | hasPermission)\"\r\n ></vdr-configurable-input>\r\n </ng-container>\r\n </div>\r\n\r\n <div *vdrIfPermissions=\"updatePermission\">\r\n <vdr-dropdown>\r\n <button class=\"btn btn-outline\" vdrDropdownTrigger>\r\n <clr-icon shape=\"plus\"></clr-icon>\r\n {{ 'marketing.add-condition' | translate }}\r\n </button>\r\n <vdr-dropdown-menu vdrPosition=\"bottom-left\">\r\n <button\r\n *ngFor=\"let filter of allFilters\"\r\n type=\"button\"\r\n vdrDropdownItem\r\n (click)=\"addFilter(filter)\"\r\n >\r\n {{ filter.description }}\r\n </button>\r\n </vdr-dropdown-menu>\r\n </vdr-dropdown>\r\n </div>\r\n </div>\r\n <div class=\"clr-col\">\r\n <vdr-collection-contents\r\n [collectionId]=\"id\"\r\n [parentId]=\"parentId$ | async\"\r\n [updatedFilters]=\"updatedFilters$ | async\"\r\n [inheritFilters]=\"inheritFilters$ | async\"\r\n [previewUpdatedFilters]=\"livePreview\"\r\n #collectionContents\r\n >\r\n <ng-template let-count>\r\n <div class=\"contents-title\">\r\n {{ 'catalog.collection-contents' | translate }} ({{\r\n 'common.results-count' | translate: {count: count}\r\n }})\r\n </div>\r\n <clr-checkbox-wrapper [class.disabled]=\"detailForm.get('filters')?.pristine\">\r\n <input\r\n type=\"checkbox\"\r\n clrCheckbox\r\n [ngModelOptions]=\"{ standalone: true }\"\r\n [disabled]=\"detailForm.get('filters')?.pristine\"\r\n [ngModel]=\"livePreview\"\r\n (ngModelChange)=\"toggleLivePreview()\"\r\n />\r\n <label>{{ 'catalog.live-preview-contents' | translate }}</label>\r\n </clr-checkbox-wrapper>\r\n </ng-template>\r\n </vdr-collection-contents>\r\n </div>\r\n </div>\r\n</form>\r\n","import {\r\n ChangeDetectionStrategy,\r\n ChangeDetectorRef,\r\n Component,\r\n OnDestroy,\r\n OnInit,\r\n ViewChild,\r\n} from '@angular/core';\r\nimport { FormArray, FormBuilder, FormControl, FormGroup, Validators } from '@angular/forms';\r\nimport { ActivatedRoute, Router } from '@angular/router';\r\nimport { marker as _ } from '@biesbjerg/ngx-translate-extract-marker';\r\nimport {\r\n Asset,\r\n BaseDetailComponent,\r\n Collection,\r\n CollectionFragment,\r\n ConfigurableOperation,\r\n ConfigurableOperationDefinition,\r\n ConfigurableOperationInput,\r\n CreateCollectionInput,\r\n createUpdatedTranslatable,\r\n CustomFieldConfig,\r\n DataService,\r\n encodeConfigArgValue,\r\n findTranslation,\r\n getConfigArgValue,\r\n LanguageCode,\r\n LocalStorageService,\r\n ModalService,\r\n NotificationService,\r\n Permission,\r\n ServerConfigService,\r\n unicodePatternValidator,\r\n UpdateCollectionInput,\r\n} from '@vendure/admin-ui/core';\r\nimport { normalizeString } from '@vendure/common/lib/normalize-string';\r\nimport { combineLatest, merge, Observable, of, Subject } from 'rxjs';\r\nimport { debounceTime, distinctUntilChanged, filter, map, mergeMap, switchMap, take } from 'rxjs/operators';\r\n\r\nimport { CollectionContentsComponent } from '../collection-contents/collection-contents.component';\r\n\r\n@Component({\r\n selector: 'vdr-collection-detail',\r\n templateUrl: './collection-detail.component.html',\r\n styleUrls: ['./collection-detail.component.scss'],\r\n changeDetection: ChangeDetectionStrategy.OnPush,\r\n})\r\nexport class CollectionDetailComponent\r\n extends BaseDetailComponent<CollectionFragment>\r\n implements OnInit, OnDestroy\r\n{\r\n customFields: CustomFieldConfig[];\r\n detailForm: FormGroup;\r\n assetChanges: { assets?: Asset[]; featuredAsset?: Asset } = {};\r\n filters: ConfigurableOperation[] = [];\r\n allFilters: ConfigurableOperationDefinition[] = [];\r\n updatedFilters$: Observable<ConfigurableOperationInput[]>;\r\n inheritFilters$: Observable<boolean>;\r\n livePreview = false;\r\n parentId$: Observable<string | undefined>;\r\n readonly updatePermission = [Permission.UpdateCatalog, Permission.UpdateCollection];\r\n private filterRemoved$ = new Subject<void>();\r\n @ViewChild('collectionContents') contentsComponent: CollectionContentsComponent;\r\n\r\n constructor(\r\n router: Router,\r\n route: ActivatedRoute,\r\n serverConfigService: ServerConfigService,\r\n private changeDetector: ChangeDetectorRef,\r\n protected dataService: DataService,\r\n private formBuilder: FormBuilder,\r\n private notificationService: NotificationService,\r\n private modalService: ModalService,\r\n private localStorageService: LocalStorageService,\r\n ) {\r\n super(route, router, serverConfigService, dataService);\r\n this.customFields = this.getCustomFieldConfig('Collection');\r\n this.detailForm = this.formBuilder.group({\r\n name: ['', Validators.required],\r\n slug: ['', unicodePatternValidator(/^[\\p{Letter}0-9_-]+$/)],\r\n description: '',\r\n visible: false,\r\n inheritFilters: true,\r\n filters: this.formBuilder.array([]),\r\n customFields: this.formBuilder.group(\r\n this.customFields.reduce((hash, field) => ({ ...hash, [field.name]: '' }), {}),\r\n ),\r\n });\r\n this.livePreview = this.localStorageService.get('livePreviewCollectionContents') ?? false;\r\n }\r\n\r\n ngOnInit() {\r\n this.init();\r\n this.dataService.collection.getCollectionFilters().single$.subscribe(res => {\r\n this.allFilters = res.collectionFilters;\r\n });\r\n const filtersFormArray = this.detailForm.get('filters') as FormArray;\r\n const inheritFiltersControl = this.detailForm.get('inheritFilters') as FormControl;\r\n this.inheritFilters$ = inheritFiltersControl.valueChanges.pipe(distinctUntilChanged());\r\n this.updatedFilters$ = merge(filtersFormArray.statusChanges, this.filterRemoved$).pipe(\r\n debounceTime(200),\r\n filter(() => filtersFormArray.touched),\r\n map(() =>\r\n this.mapOperationsToInputs(this.filters, filtersFormArray.value).filter(_filter => {\r\n // ensure all the arguments have valid values. E.g. a newly-added\r\n // filter will not yet have valid values\r\n for (const arg of _filter.arguments) {\r\n if (arg.value === '') {\r\n return false;\r\n }\r\n }\r\n return true;\r\n }),\r\n ),\r\n );\r\n this.parentId$ = this.route.paramMap.pipe(\r\n map(pm => pm.get('parentId') || undefined),\r\n switchMap(parentId => {\r\n if (parentId) {\r\n return of(parentId);\r\n } else {\r\n return this.entity$.pipe(map(collection => collection.parent?.id));\r\n }\r\n }),\r\n );\r\n }\r\n\r\n ngOnDestroy() {\r\n this.destroy();\r\n }\r\n\r\n getFilterDefinition(_filter: ConfigurableOperation): ConfigurableOperationDefinition | undefined {\r\n return this.allFilters.find(f => f.code === _filter.code);\r\n }\r\n\r\n assetsChanged(): boolean {\r\n return !!Object.values(this.assetChanges).length;\r\n }\r\n\r\n /**\r\n * If creating a new Collection, automatically generate the slug based on the collection name.\r\n */\r\n updateSlug(nameValue: string) {\r\n combineLatest(this.entity$, this.languageCode$)\r\n .pipe(take(1))\r\n .subscribe(([entity, languageCode]) => {\r\n const slugControl = this.detailForm.get(['slug']);\r\n const currentTranslation = findTranslation(entity, languageCode);\r\n const currentSlugIsEmpty = !currentTranslation || !currentTranslation.slug;\r\n if (slugControl && slugControl.pristine && currentSlugIsEmpty) {\r\n slugControl.setValue(normalizeString(`${nameValue}`, '-'));\r\n }\r\n });\r\n }\r\n\r\n addFilter(collectionFilter: ConfigurableOperation) {\r\n const filtersArray = this.detailForm.get('filters') as FormArray;\r\n const argsHash = collectionFilter.args.reduce(\r\n (output, arg) => ({\r\n ...output,\r\n [arg.name]: getConfigArgValue(arg.value),\r\n }),\r\n {},\r\n );\r\n filtersArray.push(\r\n this.formBuilder.control({\r\n code: collectionFilter.code,\r\n args: argsHash,\r\n }),\r\n );\r\n this.filters.push({\r\n code: collectionFilter.code,\r\n args: collectionFilter.args.map(a => ({ name: a.name, value: getConfigArgValue(a.value) })),\r\n });\r\n }\r\n\r\n removeFilter(index: number) {\r\n const filtersArray = this.detailForm.get('filters') as FormArray;\r\n if (index !== -1) {\r\n filtersArray.removeAt(index);\r\n filtersArray.markAsDirty();\r\n filtersArray.markAsTouched();\r\n this.filters.splice(index, 1);\r\n this.filterRemoved$.next();\r\n }\r\n }\r\n\r\n create() {\r\n if (!this.detailForm.dirty) {\r\n return;\r\n }\r\n combineLatest(this.entity$, this.languageCode$)\r\n .pipe(\r\n take(1),\r\n mergeMap(([category, languageCode]) => {\r\n const input = this.getUpdatedCollection(\r\n category,\r\n this.detailForm,\r\n languageCode,\r\n ) as CreateCollectionInput;\r\n const parentId = this.route.snapshot.paramMap.get('parentId');\r\n if (parentId) {\r\n input.parentId = parentId;\r\n }\r\n return this.dataService.collection.createCollection(input);\r\n }),\r\n )\r\n .subscribe(\r\n data => {\r\n this.notificationService.success(_('common.notify-create-success'), {\r\n entity: 'Collection',\r\n });\r\n this.assetChanges = {};\r\n this.detailForm.markAsPristine();\r\n this.changeDetector.markForCheck();\r\n this.router.navigate(['../', data.createCollection.id], { relativeTo: this.route });\r\n },\r\n err => {\r\n this.notificationService.error(_('common.notify-create-error'), {\r\n entity: 'Collection',\r\n });\r\n },\r\n );\r\n }\r\n\r\n save() {\r\n combineLatest(this.entity$, this.languageCode$)\r\n .pipe(\r\n take(1),\r\n mergeMap(([category, languageCode]) => {\r\n const input = this.getUpdatedCollection(\r\n category,\r\n this.detailForm,\r\n languageCode,\r\n ) as UpdateCollectionInput;\r\n return this.dataService.collection.updateCollection(input);\r\n }),\r\n )\r\n .subscribe(\r\n () => {\r\n this.assetChanges = {};\r\n this.detailForm.markAsPristine();\r\n this.changeDetector.markForCheck();\r\n this.notificationService.success(_('common.notify-update-success'), {\r\n entity: 'Collection',\r\n });\r\n this.contentsComponent.refresh();\r\n },\r\n err => {\r\n this.notificationService.error(_('common.notify-update-error'), {\r\n entity: 'Collection',\r\n });\r\n },\r\n );\r\n }\r\n\r\n canDeactivate(): boolean {\r\n return super.canDeactivate() && !this.assetChanges.assets && !this.assetChanges.featuredAsset;\r\n }\r\n\r\n toggleLivePreview() {\r\n this.livePreview = !this.livePreview;\r\n this.localStorageService.set('livePreviewCollectionContents', this.livePreview);\r\n }\r\n\r\n trackByFn(index: number, item: ConfigurableOperation) {\r\n return JSON.stringify(item);\r\n }\r\n\r\n /**\r\n * Sets the values of the form on changes to the category or current language.\r\n */\r\n protected setFormValues(entity: CollectionFragment, languageCode: LanguageCode) {\r\n const currentTranslation = findTranslation(entity, languageCode);\r\n\r\n this.detailForm.patchValue({\r\n name: currentTranslation ? currentTranslation.name : '',\r\n slug: currentTranslation ? currentTranslation.slug : '',\r\n description: currentTranslation ? currentTranslation.description : '',\r\n visible: !entity.isPrivate,\r\n inheritFilters: entity.inheritFilters,\r\n });\r\n\r\n const formArray = this.detailForm.get('filters') as FormArray;\r\n if (formArray.length !== entity.filters.length) {\r\n formArray.clear();\r\n this.filters = [];\r\n entity.filters.forEach(f => this.addFilter(f));\r\n }\r\n\r\n if (this.customFields.length) {\r\n this.setCustomFieldFormValues(\r\n this.customFields,\r\n this.detailForm.get(['customFields']),\r\n entity,\r\n currentTranslation,\r\n );\r\n }\r\n }\r\n\r\n /**\r\n * Given a category and the value of the form, this method creates an updated copy of the category which\r\n * can then be persisted to the API.\r\n */\r\n private getUpdatedCollection(\r\n category: CollectionFragment,\r\n form: FormGroup,\r\n languageCode: LanguageCode,\r\n ): CreateCollectionInput | UpdateCollectionInput {\r\n const updatedCategory = createUpdatedTranslatable({\r\n translatable: category,\r\n updatedFields: form.value,\r\n customFieldConfig: this.customFields,\r\n languageCode,\r\n defaultTranslation: {\r\n languageCode,\r\n name: category.name || '',\r\n slug: category.slug || '',\r\n description: category.description || '',\r\n },\r\n });\r\n return {\r\n ...updatedCategory,\r\n assetIds: this.assetChanges.assets?.map(a => a.id),\r\n featuredAssetId: this.assetChanges.featuredAsset?.id,\r\n isPrivate: !form.value.visible,\r\n filters: this.mapOperationsToInputs(this.filters, this.detailForm.value.filters),\r\n };\r\n }\r\n\r\n /**\r\n * Maps an array of conditions or actions to the input format expected by the GraphQL API.\r\n */\r\n private mapOperationsToInputs(\r\n operations: ConfigurableOperation[],\r\n formValueOperations: any,\r\n ): ConfigurableOperationInput[] {\r\n return operations.map((o, i) => {\r\n return {\r\n code: o.code,\r\n arguments: Object.entries(formValueOperations[i].args).map(([name, value], j) => {\r\n return {\r\n name,\r\n value: encodeConfigArgValue(value),\r\n };\r\n }),\r\n };\r\n });\r\n }\r\n}\r\n","export type HasParent = { id: string; parent?: { id: string } | null };\r\nexport type TreeNode<T extends HasParent> = T & { children: Array<TreeNode<T>>; expanded: boolean };\r\nexport type RootNode<T extends HasParent> = { id?: string; children: Array<TreeNode<T>> };\r\n\r\n/**\r\n * Builds a tree from an array of nodes which have a parent.\r\n * Based on https://stackoverflow.com/a/31247960/772859, modified to preserve ordering.\r\n */\r\nexport function arrayToTree<T extends HasParent>(\r\n nodes: T[],\r\n currentState?: RootNode<T>,\r\n expandedIds: string[] = [],\r\n): RootNode<T> {\r\n const topLevelNodes: Array<TreeNode<T>> = [];\r\n const mappedArr: { [id: string]: TreeNode<T> } = {};\r\n const currentStateMap = treeToMap(currentState);\r\n\r\n // First map the nodes of the array to an object -> create a hash table.\r\n for (const node of nodes) {\r\n mappedArr[node.id] = { ...(node as any), children: [] };\r\n }\r\n\r\n for (const id of nodes.map(n => n.id)) {\r\n if (mappedArr.hasOwnProperty(id)) {\r\n const mappedElem = mappedArr[id];\r\n mappedElem.expanded = currentStateMap.get(id)?.expanded ?? expandedIds.includes(id);\r\n const parent = mappedElem.parent;\r\n if (!parent) {\r\n continue;\r\n }\r\n // If the element is not at the root level, add it to its parent array of children.\r\n const parentIsRoot = !mappedArr[parent.id];\r\n if (!parentIsRoot) {\r\n if (mappedArr[parent.id]) {\r\n mappedArr[parent.id].children.push(mappedElem);\r\n } else {\r\n mappedArr[parent.id] = { children: [mappedElem] } as any;\r\n }\r\n } else {\r\n topLevelNodes.push(mappedElem);\r\n }\r\n }\r\n }\r\n // tslint:disable-next-line:no-non-null-assertion\r\n const rootId = topLevelNodes.length ? topLevelNodes[0].parent!.id : undefined;\r\n return { id: rootId, children: topLevelNodes };\r\n}\r\n\r\n/**\r\n * Converts an existing tree (as generated by the arrayToTree function) into a flat\r\n * Map. This is used to persist certain states (e.g. `expanded`) when re-building the\r\n * tree.\r\n */\r\nfunction treeToMap<T extends HasParent>(tree?: RootNode<T>): Map<string, TreeNode<T>> {\r\n const nodeMap = new Map<string, TreeNode<T>>();\r\n function visit(node: TreeNode<T>) {\r\n nodeMap.set(node.id, node);\r\n node.children.forEach(visit);\r\n }\r\n if (tree) {\r\n visit(tree as TreeNode<T>);\r\n }\r\n return nodeMap;\r\n}\r\n","import { CdkDragDrop } from '@angular/cdk/drag-drop';\r\nimport { Injectable, OnDestroy } from '@angular/core';\r\nimport { Observable, Subject } from 'rxjs';\r\n\r\nimport { RootNode, TreeNode } from './array-to-tree';\r\nimport { CollectionPartial, RearrangeEvent } from './collection-tree.types';\r\n\r\n/**\r\n * Facilitates communication between the CollectionTreeComponent and child CollectionTreeNodeComponents\r\n * without introducing a cyclic dependency.\r\n */\r\n@Injectable()\r\nexport class CollectionTreeService implements OnDestroy {\r\n private allMoveListItems: Array<{ path: string; id: string; ancestorIdPath: Set<string> }> = [];\r\n private collectionTree: RootNode<CollectionPartial>;\r\n private _rearrange$ = new Subject<RearrangeEvent>();\r\n private _delete$ = new Subject<string>();\r\n\r\n public rearrange$: Observable<RearrangeEvent>;\r\n public delete$: Observable<string>;\r\n\r\n constructor() {\r\n this.rearrange$ = this._rearrange$.asObservable();\r\n this.delete$ = this._delete$.asObservable();\r\n }\r\n\r\n ngOnDestroy() {\r\n this._rearrange$.complete();\r\n this._delete$.complete();\r\n }\r\n\r\n setCollectionTree(tree: RootNode<CollectionPartial>) {\r\n this.collectionTree = tree;\r\n }\r\n\r\n resetMoveList() {\r\n this.allMoveListItems = [];\r\n }\r\n\r\n getMoveListItems(collection: CollectionPartial) {\r\n if (this.allMoveListItems.length === 0) {\r\n this.allMoveListItems = this.calculateAllMoveListItems();\r\n }\r\n return this.allMoveListItems.filter(\r\n item =>\r\n item.id !== collection.id &&\r\n !item.ancestorIdPath.has(collection.id) &&\r\n item.id !== collection.parent?.id,\r\n );\r\n }\r\n\r\n onDrop(event: CdkDragDrop<CollectionPartial | RootNode<CollectionPartial>>) {\r\n const item = event.item.data as CollectionPartial;\r\n const newParent = event.container.data;\r\n const newParentId = newParent.id;\r\n if (newParentId == null) {\r\n throw new Error(`Could not determine the ID of the root Collection`);\r\n }\r\n this._rearrange$.next({\r\n collectionId: item.id,\r\n parentId: newParentId,\r\n index: event.currentIndex,\r\n });\r\n }\r\n\r\n onMove(event: RearrangeEvent) {\r\n this._rearrange$.next(event);\r\n }\r\n\r\n onDelete(id: string) {\r\n this._delete$.next(id);\r\n }\r\n\r\n private calculateAllMoveListItems() {\r\n const visit = (\r\n node: TreeNode<any>,\r\n parentPath: string[],\r\n ancestorIdPath: Set<string>,\r\n output: Array<{ path: string; id: string; ancestorIdPath: Set<string> }>,\r\n ) => {\r\n const path = parentPath.concat(node.name);\r\n output.push({ path: path.slice(1).join(' / ') || 'root', id: node.id, ancestorIdPath });\r\n node.children.forEach(child =>\r\n visit(child, path, new Set<string>([...ancestorIdPath, node.id]), output),\r\n );\r\n return output;\r\n };\r\n return visit(this.collectionTree, [], new Set<string>(), []);\r\n }\r\n}\r\n","<div\r\n cdkDropList\r\n class=\"tree-node\"\r\n #dropList\r\n [cdkDropListData]=\"collectionTree\"\r\n [cdkDropListDisabled]=\"!(hasUpdatePermission$ | async)\"\r\n (cdkDropListDropped)=\"drop($event)\"\r\n>\r\n <div\r\n class=\"collection\"\r\n [class.private]=\"collection.isPrivate\"\r\n *ngFor=\"let collection of collectionTree.children; index as i; trackBy: trackByFn\"\r\n cdkDrag\r\n [cdkDragData]=\"collection\"\r\n >\r\n <div\r\n class=\"collection-detail\"\r\n [ngClass]=\"'depth-' + depth\"\r\n [class.active]=\"collection.id === activeCollectionId\"\r\n >\r\n <div>\r\n <input\r\n type=\"checkbox\"\r\n clrCheckbox\r\n [checked]=\"selectionManager.isSelected(collection)\"\r\n (click)=\"selectionManager.toggleSelection(collection, $event)\"\r\n />\r\n </div>\r\n <div class=\"name\">\r\n <button\r\n class=\"icon-button folder-button\"\r\n [disabled]=\"expandAll\"\r\n *ngIf=\"collection.children?.length; else folderSpacer\"\r\n (click)=\"toggleExpanded(collection)\"\r\n >\r\n <clr-icon shape=\"folder\" *ngIf=\"!collection.expanded && !expandAll\"></clr-icon>\r\n <clr-icon shape=\"folder-open\" *ngIf=\"collection.expanded || expandAll\"></clr-icon>\r\n </button>\r\n <ng-template #folderSpacer>\r\n <div class=\"folder-button-spacer\"></div>\r\n </ng-template>\r\n {{ collection.name }}\r\n </div>\r\n <div class=\"flex-spacer\"></div>\r\n <vdr-chip *ngIf=\"collection.isPrivate\">{{ 'catalog.private' | translate }}</vdr-chip>\r\n <a\r\n class=\"btn btn-link btn-sm\"\r\n [routerLink]=\"['./', { contents: collection.id }]\"\r\n queryParamsHandling=\"preserve\"\r\n >\r\n <clr-icon shape=\"view-list\"></clr-icon>\r\n {{ 'catalog.view-contents' | translate }}\r\n </a>\r\n <a class=\"btn btn-link btn-sm\" [routerLink]=\"['/catalog/collections/', collection.id]\">\r\n <clr-icon shape=\"edit\"></clr-icon>\r\n {{ 'common.edit' | translate }}\r\n </a>\r\n <div class=\"drag-handle\" cdkDragHandle *vdrIfPermissions=\"['UpdateCatalog', 'UpdateCollection']\">\r\n <clr-icon shape=\"drag-handle\" size=\"24\"></clr-icon>\r\n </div>\r\n <vdr-dropdown>\r\n <button class=\"icon-button\" vdrDropdownTrigger (click)=\"getMoveListItems(collection)\">\r\n <clr-icon shape=\"ellipsis-vertical\"></clr-icon>\r\n </button>\r\n <vdr-dropdown-menu vdrPosition=\"bottom-right\">\r\n <a\r\n class=\"dropdown-item\"\r\n [routerLink]=\"['./', 'create', { parentId: collection.id }]\"\r\n *vdrIfPermissions=\"['CreateCatalog', 'CreateCollection']\"\r\n >\r\n <clr-icon shape=\"plus\"></clr-icon>\r\n {{ 'catalog.create-new-collection' | translate }}\r\n </a>\r\n <div class=\"dropdown-divider\"></div>\r\n <button\r\n type=\"button\"\r\n vdrDropdownItem\r\n [disabled]=\"i === 0 || !(hasUpdatePermission$ | async)\"\r\n (click)=\"moveUp(collection, i)\"\r\n >\r\n <clr-icon shape=\"caret up\"></clr-icon>\r\n {{ 'catalog.move-up' | translate }}\r\n </button>\r\n <button\r\n type=\"button\"\r\n vdrDropdownItem\r\n [disabled]=\"\r\n i === collectionTree.children.length - 1 || !(hasUpdatePermission$ | async)\r\n \"\r\n (click)=\"moveDown(collection, i)\"\r\n >\r\n <clr-icon shape=\"caret down\"></clr-icon>\r\n {{ 'catalog.move-down' | translate }}\r\n </button>\r\n <h4 class=\"dropdown-header\">{{ 'catalog.move-to' | translate }}</h4>\r\n <button\r\n type=\"button\"\r\n vdrDropdownItem\r\n *ngFor=\"let item of moveListItems\"\r\n (click)=\"move(collection, item.id)\"\r\n [disabled]=\"!(hasUpdatePermission$ | async)\"\r\n >\r\n <div class=\"move-to-item\">\r\n <div class=\"move-icon\">\r\n <clr-icon shape=\"child-arrow\"></clr-icon>\r\n </div>\r\n <div class=\"path\">\r\n {{ item.path }}\r\n </div>\r\n </div>\r\n </button>\r\n <div class=\"dropdown-divider\"></div>\r\n <button\r\n class=\"button\"\r\n vdrDropdownItem\r\n (click)=\"delete(collection.id)\"\r\n [disabled]=\"!(hasDeletePermission$ | async)\"\r\n >\r\n <clr-icon shape=\"trash\" class=\"is-danger\"></clr-icon>\r\n {{ 'common.delete' | translate }}\r\n </button>\r\n </vdr-dropdown-menu>\r\n </vdr-dropdown>\r\n </div>\r\n <vdr-collection-tree-node\r\n *ngIf=\"collection.expanded || expandAll\"\r\n [expandAll]=\"expandAll\"\r\n [collectionTree]=\"collection\"\r\n [activeCollectionId]=\"activeCollectionId\"\r\n [selectionManager]=\"selectionManager\"\r\n ></vdr-collection-tree-node>\r\n </div>\r\n</div>\r\n","import { CdkDragDrop, moveItemInArray } from '@angular/cdk/drag-drop';\r\nimport {\r\n ChangeDetectionStrategy,\r\n ChangeDetectorRef,\r\n Component,\r\n Input,\r\n OnChanges,\r\n OnDestroy,\r\n OnInit,\r\n Optional,\r\n SimpleChanges,\r\n SkipSelf,\r\n} from '@angular/core';\r\nimport { ActivatedRoute, Router } from '@angular/router';\r\nimport { DataService, Permission, SelectionManager } from '@vendure/admin-ui/core';\r\nimport { Observable, Subscription } from 'rxjs';\r\nimport { map, shareReplay } from 'rxjs/operators';\r\n\r\nimport { RootNode, TreeNode } from './array-to-tree';\r\nimport { CollectionTreeService } from './collection-tree.service';\r\nimport { CollectionPartial } from './collection-tree.types';\r\n\r\n@Component({\r\n selector: 'vdr-collection-tree-node',\r\n templateUrl: './collection-tree-node.component.html',\r\n styleUrls: ['./collection-tree-node.component.scss'],\r\n changeDetection: ChangeDetectionStrategy.OnPush,\r\n})\r\nexport class CollectionTreeNodeComponent implements OnInit, OnChanges, OnDestroy {\r\n depth = 0;\r\n parentName: string;\r\n @Input() collectionTree: TreeNode<CollectionPartial>;\r\n @Input() activeCollectionId: string;\r\n @Input() expandAll = false;\r\n @Input() selectionManager: SelectionManager<CollectionPartial>;\r\n hasUpdatePermission$: Observable<boolean>;\r\n hasDeletePermission$: Observable<boolean>;\r\n moveListItems: Array<{ path: string; id: string }> = [];\r\n private subscription: Subscription;\r\n\r\n constructor(\r\n @SkipSelf() @Optional() private parent: CollectionTreeNodeComponent,\r\n private dataService: DataService,\r\n private collectionTreeService: CollectionTreeService,\r\n private router: Router,\r\n private route: ActivatedRoute,\r\n private changeDetectorRef: ChangeDetectorRef,\r\n ) {\r\n if (parent) {\r\n this.depth = parent.depth + 1;\r\n }\r\n }\r\n\r\n ngOnInit() {\r\n this.parentName = this.collectionTree.name || '<root>';\r\n const permissions$ = this.dataService.client\r\n .userStatus()\r\n .mapStream(data => data.userStatus.permissions)\r\n .pipe(shareReplay(1));\r\n this.hasUpdatePermission$ = permissions$.pipe(\r\n map(\r\n perms =>\r\n perms.includes(Permission.UpdateCatalog) || perms.includes(Permission.UpdateCollection),\r\n ),\r\n );\r\n this.hasDeletePermission$ = permissions$.pipe(\r\n map(\r\n perms =>\r\n perms.includes(Permission.DeleteCatalog) || perms.includes(Permission.DeleteCollection),\r\n ),\r\n );\r\n this.subscription = this.selectionManager?.selectionChanges$.subscribe(() =>\r\n this.changeDetectorRef.markForCheck(),\r\n );\r\n }\r\n\r\n ngOnChanges(changes: SimpleChanges) {\r\n const expandAllChange = changes['expandAll'];\r\n if (expandAllChange) {\r\n if (expandAllChange.previousValue === true && expandAllChange.currentValue === false) {\r\n this.collectionTree.children.forEach(c => (c.expanded = false));\r\n }\r\n }\r\n }\r\n\r\n ngOnDestroy() {\r\n this.subscription?.unsubscribe();\r\n }\r\n\r\n trackByFn(index: number, item: CollectionPartial) {\r\n return item.id;\r\n }\r\n\r\n toggleExpanded(collection: TreeNode<CollectionPartial>) {\r\n collection.expanded = !collection.expanded;\r\n let expandedIds = this.route.snapshot.queryParamMap.get('expanded')?.split(',') ?? [];\r\n if (collection.expanded) {\r\n expandedIds.push(collection.id);\r\n } else {\r\n expandedIds = expandedIds.filter(id => id !== collection.id);\r\n }\r\n this.router.navigate(['./'], {\r\n queryParams: {\r\n expanded: expandedIds.filter(id => !!id).join(','),\r\n },\r\n queryParamsHandling: 'merge',\r\n relativeTo: this.route,\r\n });\r\n }\r\n\r\n getMoveListItems(collection: CollectionPartial) {\r\n this.moveListItems = this.collectionTreeService.getMoveListItems(collection);\r\n }\r\n\r\n move(collection: CollectionPartial, parentId: string) {\r\n this.collectionTreeService.onMove({\r\n index: 0,\r\n parentId,\r\n collectionId: collection.id,\r\n });\r\n }\r\n\r\n moveUp(collection: CollectionPartial, currentIndex: number) {\r\n if (!collection.parent) {\r\n return;\r\n }\r\n this.collectionTreeService.onMove({\r\n index: currentIndex - 1,\r\n parentId: collection.parent.id,\r\n collectionId: collection.id,\r\n });\r\n }\r\n\r\n moveDown(collection: CollectionPartial, currentIndex: number) {\r\n if (!collection.parent) {\r\n return;\r\n }\r\n this.collectionTreeService.onMove({\r\n index: currentIndex + 1,\r\n parentId: collection.parent.id,\r\n collectionId: collection.id,\r\n });\r\n }\r\n\r\n drop(event: CdkDragDrop<CollectionPartial | RootNode<CollectionPartial>>) {\r\n moveItemInArray(this.collectionTree.children, event.previousIndex, event.currentIndex);\r\n this.collectionTreeService.onDrop(event);\r\n }\r\n\r\n delete(id: string) {\r\n this.collectionTreeService.onDelete(id);\r\n }\r\n}\r\n","<vdr-collection-tree-node\r\n *ngIf=\"collectionTree\"\r\n cdkDropListGroup\r\n [expandAll]=\"expandAll\"\r\n [collectionTree]=\"collectionTree\"\r\n [selectionManager]=\"selectionManager\"\r\n [activeCollectionId]=\"activeCollectionId\"\r\n></vdr-collection-tree-node>\r\n","import {\r\n ChangeDetectionStrategy,\r\n Component,\r\n EventEmitter,\r\n Input,\r\n OnChanges,\r\n OnInit,\r\n Output,\r\n SimpleChanges,\r\n} from '@angular/core';\r\nimport { Collection, SelectionManager } from '@vendure/admin-ui/core';\r\n\r\nimport { arrayToTree, RootNode } from './array-to-tree';\r\nimport { CollectionTreeService } from './collection-tree.service';\r\nimport { CollectionPartial, RearrangeEvent } from './collection-tree.types';\r\n\r\n@Component({\r\n selector: 'vdr-collection-tree',\r\n templateUrl: 'collection-tree.component.html',\r\n styleUrls: ['./collection-tree.component.scss'],\r\n changeDetection: ChangeDetectionStrategy.OnPush,\r\n providers: [CollectionTreeService],\r\n})\r\nexport class CollectionTreeComponent implements OnInit, OnChanges {\r\n @Input() collections: CollectionPartial[];\r\n @Input() activeCollectionId: string;\r\n @Input() expandAll = false;\r\n @Input() expandedIds: string[] = [];\r\n @Input() selectionManager: SelectionManager<CollectionPartial>;\r\n @Output() rearrange = new EventEmitter<RearrangeEvent>();\r\n @Output() deleteCollection = new EventEmitter<string>();\r\n collectionTree: RootNode<CollectionPartial>;\r\n\r\n constructor(private collectionTreeService: CollectionTreeService) {}\r\n\r\n ngOnChanges(changes: SimpleChanges) {\r\n if ('collections' in changes && this.collections) {\r\n this.collectionTree = arrayToTree(this.collections, this.collectionTree, this.expandedIds);\r\n this.collectionTreeService.setCollectionTree(this.collectionTree);\r\n this.collectionTreeService.resetMoveList();\r\n }\r\n }\r\n\r\n ngOnInit() {\r\n this.collectionTreeService.rearrange$.subscribe(event => this.rearrange.emit(event));\r\n this.collectionTreeService.delete$.subscribe(id => this.deleteCollection.emit(id));\r\n }\r\n}\r\n","<vdr-action-bar>\r\n <vdr-ab-left>\r\n <div class=\"\">\r\n <input\r\n type=\"text\"\r\n name=\"searchTerm\"\r\n [formControl]=\"filterTermControl\"\r\n [placeholder]=\"'catalog.filter-by-name' | translate\"\r\n class=\"clr-input search-input\"\r\n />\r\n <div class=\"flex center\">\r\n <clr-toggle-wrapper\r\n class=\"expand-all-toggle mt2\"\r\n >\r\n <input type=\"checkbox\" clrToggle [(ngModel)]=\"expandAll\" (change)=\"toggleExpandAll()\" />\r\n <label>\r\n {{ 'catalog.expand-all-collections' | translate }}\r\n </label>\r\n </clr-toggle-wrapper>\r\n <vdr-language-selector\r\n class=\"mt2\"\r\n [availableLanguageCodes]=\"availableLanguages$ | async\"\r\n [currentLanguageCode]=\"contentLanguage$ | async\"\r\n (languageCodeChange)=\"setLanguage($event)\"\r\n ></vdr-language-selector>\r\n </div>\r\n </div>\r\n </vdr-ab-left>\r\n <vdr-ab-right>\r\n <vdr-action-bar-items locationId=\"collection-list\"></vdr-action-bar-items>\r\n <a\r\n class=\"btn btn-primary\"\r\n *vdrIfPermissions=\"['CreateCatalog', 'CreateCollection']\"\r\n [routerLink]=\"['./create']\"\r\n >\r\n <clr-icon shape=\"plus\"></clr-icon>\r\n {{ 'catalog.create-new-collection' | translate }}\r\n </a>\r\n </vdr-ab-right>\r\n</vdr-action-bar>\r\n<div class=\"bulk-select-controls\">\r\n <input\r\n type=\"checkbox\"\r\n clrCheckbox\r\n [checked]=\"selectionManager.areAllCurrentItemsSelected()\"\r\n (click)=\"selectionManager.toggleSelectAll()\"\r\n />\r\n <vdr-bulk-action-menu\r\n class=\"ml2\"\r\n locationId=\"collection-list\"\r\n [hostComponent]=\"this\"\r\n [selectionManager]=\"selectionManager\"\r\n ></vdr-bulk-action-menu>\r\n</div>\r\n<div class=\"collection-wrapper\">\r\n <vdr-collection-tree\r\n [collections]=\"items$ | async\"\r\n [activeCollectionId]=\"activeCollectionId$ | async\"\r\n [expandAll]=\"expandAll\"\r\n [expandedIds]=\"expandedIds\"\r\n [selectionManager]=\"selectionManager\"\r\n (rearrange)=\"onRearrange($event)\"\r\n (deleteCollection)=\"deleteCollection($event)\"\r\n ></vdr-collection-tree>\r\n\r\n <div class=\"collection-contents\" [class.expanded]=\"activeCollectionId$ | async\">\r\n <vdr-collection-contents [collectionId]=\"activeCollectionId$ | async\">\r\n <ng-template let-count>\r\n <div class=\"collection-title\">\r\n {{ activeCollectionTitle$ | async }} ({{\r\n 'common.results-count' | translate: { count: count }\r\n }})\r\n </div>\r\n <button type=\"button\" class=\"close-button\" (click)=\"closeContents()\">\r\n <clr-icon shape=\"close\"></clr-icon>\r\n </button>\r\n </ng-template>\r\n </vdr-collection-contents>\r\n </div>\r\n</div>\r\n","import { ChangeDetectionStrategy, ChangeDetectorRef, Component, OnDestroy, OnInit } from '@angular/core';\r\nimport { FormControl } from '@angular/forms';\r\nimport { ActivatedRoute, Router } from '@angular/router';\r\nimport { marker as _ } from '@biesbjerg/ngx-translate-extract-marker';\r\nimport {\r\n DataService,\r\n GetCollectionListQuery,\r\n ItemOf,\r\n LanguageCode,\r\n ModalService,\r\n NotificationService,\r\n QueryResult,\r\n SelectionManager,\r\n ServerConfigService,\r\n} from '@vendure/admin-ui/core';\r\nimport { combineLatest, EMPTY, Observable, Subject } from 'rxjs';\r\nimport {\r\n debounceTime,\r\n distinctUntilChanged,\r\n map,\r\n shareReplay,\r\n switchMap,\r\n take,\r\n takeUntil,\r\n tap,\r\n} from 'rxjs/operators';\r\n\r\nimport { CollectionPartial, RearrangeEvent } from '../collection-tree/collection-tree.types';\r\n\r\n@Component({\r\n selector: 'vdr-collection-list',\r\n templateUrl: './collection-list.component.html',\r\n styleUrls: ['./collection-list.component.scss'],\r\n changeDetection: ChangeDetectionStrategy.OnPush,\r\n})\r\nexport class CollectionListComponent implements OnInit, OnDestroy {\r\n filterTermControl = new FormControl('');\r\n activeCollectionId$: Observable<string | null>;\r\n activeCollectionTitle$: Observable<string>;\r\n items$: Observable<Array<ItemOf<GetCollectionListQuery, 'collections'>>>;\r\n availableLanguages$: Observable<LanguageCode[]>;\r\n contentLanguage$: Observable<LanguageCode>;\r\n expandAll = false;\r\n expandedIds: string[] = [];\r\n selectionManager: SelectionManager<CollectionPartial>;\r\n private queryResult: QueryResult<any>;\r\n private destroy$ = new Subject<void>();\r\n\r\n constructor(\r\n private dataService: DataService,\r\n private notificationService: NotificationService,\r\n private modalService: ModalService,\r\n private router: Router,\r\n private route: ActivatedRoute,\r\n private serverConfigService: ServerConfigService,\r\n private changeDetectorRef: ChangeDetectorRef,\r\n ) {\r\n this.selectionManager = new SelectionManager({\r\n additiveMode: true,\r\n multiSelect: true,\r\n itemsAreEqual: (a, b) => a.id === b.id,\r\n });\r\n }\r\n\r\n ngOnInit() {\r\n this.queryResult = this.dataService.collection.getCollections(1000, 0).refetchOnChannelChange();\r\n this.items$ = this.queryResult\r\n .mapStream(data => data.collections.items)\r\n .pipe(\r\n tap(items => this.selectionManager.setCurrentItems(items)),\r\n shareReplay(1),\r\n );\r\n this.activeCollectionId$ = this.route.paramMap.pipe(\r\n map(pm => pm.get('contents')),\r\n distinctUntilChanged(),\r\n );\r\n this.expandedIds = this.route.snapshot.queryParamMap.get('expanded')?.split(',') ?? [];\r\n this.expandAll = this.route.snapshot.queryParamMap.get('expanded') === 'all';\r\n\r\n this.activeCollectionTitle$ = combineLatest(this.activeCollectionId$, this.items$).pipe(\r\n map(([id, collections]) => {\r\n if (id) {\r\n const match = collections.find(c => c.id === id);\r\n return match ? match.name : '';\r\n }\r\n return '';\r\n }),\r\n );\r\n this.availableLanguages$ = this.serverConfigService.getAvailableLanguages();\r\n this.contentLanguage$ = this.dataService.client\r\n .uiState()\r\n .mapStream(({ uiState }) => uiState.contentLanguage)\r\n .pipe(tap(() => this.refresh()));\r\n\r\n this.filterTermControl.valueChanges\r\n .pipe(debounceTime(250), takeUntil(this.destroy$))\r\n .subscribe(term => {\r\n this.router.navigate(['./'], {\r\n queryParams: {\r\n q: term || undefined,\r\n },\r\n queryParamsHandling: 'merge',\r\n relativeTo: this.route,\r\n });\r\n });\r\n\r\n this.route.queryParamMap\r\n .pipe(\r\n map(qpm => qpm.get('q')),\r\n distinctUntilChanged(),\r\n takeUntil(this.destroy$),\r\n )\r\n .subscribe(() => this.refresh());\r\n this.filterTermControl.patchValue(this.route.snapshot.queryParamMap.get('q'));\r\n }\r\n\r\n ngOnDestroy() {\r\n this.queryResult.completed$.next();\r\n this.destroy$.next(undefined);\r\n this.destroy$.complete();\r\n }\r\n\r\n toggleExpandAll() {\r\n this.router.navigate(['./'], {\r\n queryParams: {\r\n expanded: this.expandAll ? 'all' : undefined,\r\n },\r\n queryParamsHandling: 'merge',\r\n relativeTo: this.route,\r\n });\r\n }\r\n\r\n onRearrange(event: RearrangeEvent) {\r\n this.dataService.collection.moveCollection([event]).subscribe({\r\n next: () => {\r\n this.notificationService.success(_('common.notify-saved-changes'));\r\n this.refresh();\r\n },\r\n error: err => {\r\n this.notificationService.error(_('common.notify-save-changes-error'));\r\n },\r\n });\r\n }\r\n\r\n deleteCollection(id: string) {\r\n this.items$\r\n .pipe(\r\n take(1),\r\n map(items => -1 < items.findIndex(i => i.parent && i.parent.id === id)),\r\n switchMap(hasChildren => {\r\n return this.modalService.dialog({\r\n title: _('catalog.confirm-delete-collection'),\r\n body: hasChildren\r\n ? _('catalog.confirm-delete-collection-and-children-body')\r\n : undefined,\r\n buttons: [\r\n { type: 'secondary', label: _('common.cancel') },\r\n { type: 'danger', label: _('common.delete'), returnValue: true },\r\n ],\r\n });\r\n }),\r\n switchMap(response => (response ? this.dataService.collection.deleteCollection(id) : EMPTY)),\r\n )\r\n .subscribe(\r\n () => {\r\n this.notificationService.success(_('common.notify-delete-success'), {\r\n entity: 'Collection',\r\n });\r\n this.refresh();\r\n },\r\n err => {\r\n this.notificationService.error(_('common.notify-delete-error'), {\r\n entity: 'Collection',\r\n });\r\n },\r\n );\r\n }\r\n\r\n closeContents() {\r\n const params = { ...this.route.snapshot.params };\r\n delete params.contents;\r\n this.router.navigate(['./', params], { relativeTo: this.route, queryParamsHandling: 'preserve' });\r\n }\r\n\r\n setLanguage(code: LanguageCode) {\r\n this.dataService.client.setContentLanguage(code).subscribe();\r\n }\r\n\r\n refresh() {\r\n const filterTerm = this.route.snapshot.queryParamMap.get('q');\r\n this.queryResult.ref.refetch({\r\n options: {\r\n skip: 0,\r\n take: 1000,\r\n ...(filterTerm\r\n ? {\r\n filter: {\r\n name: {\r\n contains: filterTerm,\r\n },\r\n },\r\n }\r\n : {}),\r\n },\r\n });\r\n }\r\n}\r\n","<vdr-action-bar>\r\n <vdr-ab-left>\r\n <vdr-entity-info [entity]=\"entity$ | async\"></vdr-entity-info>\r\n <vdr-language-selector\r\n [disabled]=\"isNew$ | async\"\r\n [availableLanguageCodes]=\"availableLanguages$ | async\"\r\n [currentLanguageCode]=\"languageCode$ | async\"\r\n (languageCodeChange)=\"setLanguage($event)\"\r\n ></vdr-language-selector>\r\n </vdr-ab-left>\r\n\r\n <vdr-ab-right>\r\n <vdr-action-bar-items locationId=\"facet-detail\"></vdr-action-bar-items>\r\n <button\r\n class=\"btn btn-primary\"\r\n *ngIf=\"isNew$ | async; else updateButton\"\r\n (click)=\"create()\"\r\n [disabled]=\"detailForm.invalid || detailForm.pristine\"\r\n >\r\n {{ 'common.create' | translate }}\r\n </button>\r\n <ng-template #updateButton>\r\n <button\r\n *vdrIfPermissions=\"updatePermission\"\r\n class=\"btn btn-primary\"\r\n (click)=\"save()\"\r\n [disabled]=\"detailForm.invalid || detailForm.pristine\"\r\n >\r\n {{ 'common.update' | translate }}\r\n </button>\r\n </ng-template>\r\n </vdr-ab-right>\r\n</vdr-action-bar>\r\n\r\n<form class=\"form\" [formGroup]=\"detailForm\" *ngIf=\"entity$ | async as facet\">\r\n <section class=\"form-block\" formGroupName=\"facet\">\r\n <vdr-form-field [label]=\"'catalog.visibility' | translate\" for=\"visibility\">\r\n <clr-toggle-wrapper>\r\n <input\r\n type=\"checkbox\"\r\n clrToggle\r\n [vdrDisabled]=\"!(updatePermission | hasPermission)\"\r\n formControlName=\"visible\"\r\n id=\"visibility\"\r\n />\r\n <label class=\"visible-toggle\">\r\n <ng-container *ngIf=\"detailForm.value.facet.visible; else private\">{{\r\n 'catalog.public' | translate\r\n }}</ng-container>\r\n <ng-template #private>{{ 'catalog.private' | translate }}</ng-template>\r\n </label>\r\n </clr-toggle-wrapper>\r\n </vdr-form-field>\r\n <vdr-form-field [label]=\"'common.name' | translate\" for=\"name\">\r\n <input\r\n id=\"name\"\r\n type=\"text\"\r\n formControlName=\"name\"\r\n [readonly]=\"!(updatePermission | hasPermission)\"\r\n (input)=\"updateCode(facet.code, $event.target.value)\"\r\n />\r\n </vdr-form-field>\r\n <vdr-form-field\r\n [label]=\"'common.code' | translate\"\r\n for=\"code\"\r\n [readOnlyToggle]=\"updatePermission | hasPermission\"\r\n >\r\n <input\r\n id=\"code\"\r\n type=\"text\"\r\n [readonly]=\"!(updatePermission | hasPermission)\"\r\n formControlName=\"code\"\r\n />\r\n </vdr-form-field>\r\n\r\n <section formGroupName=\"customFields\" *ngIf=\"customFields.length\">\r\n <label>{{ 'common.custom-fields' | translate }}</label>\r\n <vdr-tabbed-custom-fields\r\n entityName=\"Facet\"\r\n [customFields]=\"customFields\"\r\n [customFieldsFormGroup]=\"detailForm.get(['facet', 'customFields'])\"\r\n [readonly]=\"!(updatePermission | hasPermission)\"\r\n ></vdr-tabbed-custom-fields>\r\n </section>\r\n <vdr-custom-detail-component-host\r\n locationId=\"facet-detail\"\r\n [entity$]=\"entity$\"\r\n [detailForm]=\"detailForm\"\r\n ></vdr-custom-detail-component-host>\r\n </section>\r\n\r\n <section class=\"form-block\" *ngIf=\"!(isNew$ | async)\">\r\n <label>{{ 'catalog.facet-values' | translate }}</label>\r\n\r\n <table class=\"facet-values-list table\" formArrayName=\"values\" *ngIf=\"0 < getValuesFormArray().length\">\r\n <thead>\r\n <tr>\r\n <th></th>\r\n <th>{{ 'common.name' | translate }}</th>\r\n <th>{{ 'common.code' | translate }}</th>\r\n <ng-container *ngIf=\"customValueFields.length\">\r\n <th>{{ 'common.custom-fields' | translate }}</th>\r\n </ng-container>\r\n <th></th>\r\n </tr>\r\n </thead>\r\n <tbody>\r\n <tr class=\"facet-value\" *ngFor=\"let value of values; let i = index\" [formGroupName]=\"i\">\r\n <td class=\"align-middle\">\r\n <vdr-entity-info [entity]=\"value\"></vdr-entity-info>\r\n </td>\r\n <td class=\"align-middle\">\r\n <input\r\n type=\"text\"\r\n formControlName=\"name\"\r\n [readonly]=\"!(updatePermission | hasPermission)\"\r\n (input)=\"updateValueCode(facet.values[i]?.code, $event.target.value, i)\"\r\n />\r\n </td>\r\n <td class=\"align-middle\"><input type=\"text\" formControlName=\"code\" readonly /></td>\r\n <td class=\"\" *ngIf=\"customValueFields.length\">\r\n <vdr-tabbed-custom-fields\r\n entityName=\"FacetValue\"\r\n [customFields]=\"customValueFields\"\r\n [compact]=\"true\"\r\n [customFieldsFormGroup]=\"detailForm.get(['values', i, 'customFields'])\"\r\n [readonly]=\"!(updatePermission | hasPermission)\"\r\n ></vdr-tabbed-custom-fields>\r\n </td>\r\n <td class=\"align-middle\">\r\n <vdr-dropdown>\r\n <button type=\"button\" class=\"btn btn-link btn-sm\" vdrDropdownTrigger>\r\n {{ 'common.actions' | translate }}\r\n <clr-icon shape=\"caret down\"></clr-icon>\r\n </button>\r\n <vdr-dropdown-menu vdrPosition=\"bottom-right\">\r\n <button\r\n type=\"button\"\r\n class=\"delete-button\"\r\n (click)=\"deleteFacetValue(facet.values[i]?.id, i)\"\r\n [disabled]=\"!(updatePermission | hasPermission)\"\r\n vdrDropdownItem\r\n >\r\n <clr-icon shape=\"trash\" class=\"is-danger\"></clr-icon>\r\n {{ 'common.delete' | translate }}\r\n </button>\r\n </vdr-dropdown-menu>\r\n </vdr-dropdown>\r\n </td>\r\n </tr>\r\n </tbody>\r\n </table>\r\n\r\n <div>\r\n <button\r\n type=\"button\"\r\n class=\"btn btn-secondary\"\r\n *vdrIfPermissions=\"['CreateCatalog', 'CreateFacet']\"\r\n (click)=\"addFacetValue()\"\r\n >\r\n <clr-icon shape=\"add\"></clr-icon>\r\n {{ 'catalog.add-facet-value' | translate }}\r\n </button>\r\n </div>\r\n </section>\r\n</form>\r\n","import { ChangeDetectionStrategy, ChangeDetectorRef, Component, OnDestroy, OnInit } from '@angular/core';\r\nimport { FormArray, FormBuilder, FormControl, FormGroup, Validators } from '@angular/forms';\r\nimport { ActivatedRoute, Router } from '@angular/router';\r\nimport { marker as _ } from '@biesbjerg/ngx-translate-extract-marker';\r\nimport {\r\n BaseDetailComponent,\r\n CreateFacetInput,\r\n CreateFacetValueInput,\r\n createUpdatedTranslatable,\r\n CustomFieldConfig,\r\n DataService,\r\n DeletionResult,\r\n FacetWithValuesFragment,\r\n findTranslation,\r\n LanguageCode,\r\n ModalService,\r\n NotificationService,\r\n Permission,\r\n ServerConfigService,\r\n UpdateFacetInput,\r\n UpdateFacetValueInput,\r\n} from '@vendure/admin-ui/core';\r\nimport { normalizeString } from '@vendure/common/lib/normalize-string';\r\nimport { notNullOrUndefined } from '@vendure/common/lib/shared-utils';\r\nimport { combineLatest, EMPTY, forkJoin, Observable } from 'rxjs';\r\nimport { map, mapTo, mergeMap, switchMap, take } from 'rxjs/operators';\r\n\r\n@Component({\r\n selector: 'vdr-facet-detail',\r\n templateUrl: './facet-detail.component.html',\r\n styleUrls: ['./facet-detail.component.scss'],\r\n changeDetection: ChangeDetectionStrategy.OnPush,\r\n})\r\nexport class FacetDetailComponent\r\n extends BaseDetailComponent<FacetWithValuesFragment>\r\n implements OnInit, OnDestroy\r\n{\r\n customFields: CustomFieldConfig[];\r\n customValueFields: CustomFieldConfig[];\r\n detailForm: FormGroup;\r\n values: Array<FacetWithValuesFragment['values'][number] | { name: string; code: string }>;\r\n readonly updatePermission = [Permission.UpdateCatalog, Permission.UpdateFacet];\r\n\r\n constructor(\r\n router: Router,\r\n route: ActivatedRoute,\r\n serverConfigService: ServerConfigService,\r\n private changeDetector: ChangeDetectorRef,\r\n protected dataService: DataService,\r\n private formBuilder: FormBuilder,\r\n private notificationService: NotificationService,\r\n private modalService: ModalService,\r\n ) {\r\n super(route, router, serverConfigService, dataService);\r\n this.customFields = this.getCustomFieldConfig('Facet');\r\n this.customValueFields = this.getCustomFieldConfig('FacetValue');\r\n this.detailForm = this.formBuilder.group({\r\n facet: this.formBuilder.group({\r\n code: ['', Validators.required],\r\n name: '',\r\n visible: true,\r\n customFields: this.formBuilder.group(\r\n this.customFields.reduce((hash, field) => ({ ...hash, [field.name]: '' }), {}),\r\n ),\r\n }),\r\n values: this.formBuilder.array([]),\r\n });\r\n }\r\n\r\n ngOnInit() {\r\n this.init();\r\n }\r\n\r\n ngOnDestroy() {\r\n this.destroy();\r\n }\r\n\r\n updateCode(currentCode: string, nameValue: string) {\r\n if (!currentCode) {\r\n const codeControl = this.detailForm.get(['facet', 'code']);\r\n if (codeControl && codeControl.pristine) {\r\n codeControl.setValue(normalizeString(nameValue, '-'));\r\n }\r\n }\r\n }\r\n\r\n updateValueCode(currentCode: string, nameValue: string, index: number) {\r\n if (!currentCode) {\r\n const codeControl = this.detailForm.get(['values', index, 'code']);\r\n if (codeControl && codeControl.pristine) {\r\n codeControl.setValue(normalizeString(nameValue, '-'));\r\n }\r\n }\r\n }\r\n\r\n customValueFieldIsSet(index: number, name: string): boolean {\r\n return !!this.detailForm.get(['values', index, 'customFields', name]);\r\n }\r\n\r\n getValuesFormArray(): FormArray {\r\n return this.detailForm.get('values') as FormArray;\r\n }\r\n\r\n addFacetValue() {\r\n const valuesFormArray = this.detailForm.get('values') as FormArray | null;\r\n if (valuesFormArray) {\r\n const valueGroup = this.formBuilder.group({\r\n id: '',\r\n name: ['', Validators.required],\r\n code: '',\r\n });\r\n const newValue: any = { name: '', code: '' };\r\n if (this.customValueFields.length) {\r\n const customValueFieldsGroup = new FormGroup({});\r\n newValue.customFields = {};\r\n\r\n for (const fieldDef of this.customValueFields) {\r\n const key = fieldDef.name;\r\n customValueFieldsGroup.addControl(key, new FormControl());\r\n }\r\n\r\n valueGroup.addControl('customFields', customValueFieldsGroup);\r\n }\r\n valuesFormArray.insert(valuesFormArray.length, valueGroup);\r\n this.values.push(newValue);\r\n }\r\n }\r\n\r\n create() {\r\n const facetForm = this.detailForm.get('facet');\r\n if (!facetForm || !facetForm.dirty) {\r\n return;\r\n }\r\n combineLatest(this.entity$, this.languageCode$)\r\n .pipe(\r\n take(1),\r\n mergeMap(([facet, languageCode]) => {\r\n const newFacet = this.getUpdatedFacet(\r\n facet,\r\n facetForm as FormGroup,\r\n languageCode,\r\n ) as CreateFacetInput;\r\n return this.dataService.facet.createFacet(newFacet);\r\n }),\r\n switchMap(data => this.dataService.facet.getAllFacets().single$.pipe(mapTo(data))),\r\n )\r\n .subscribe(\r\n data => {\r\n this.notificationService.success(_('common.notify-create-success'), { entity: 'Facet' });\r\n this.detailForm.markAsPristine();\r\n this.changeDetector.markForCheck();\r\n this.router.navigate(['../', data.createFacet.id], { relativeTo: this.route });\r\n },\r\n err => {\r\n this.notificationService.error(_('common.notify-create-error'), {\r\n entity: 'Facet',\r\n });\r\n },\r\n );\r\n }\r\n\r\n save() {\r\n combineLatest(this.entity$, this.languageCode$)\r\n .pipe(\r\n take(1),\r\n mergeMap(([facet, languageCode]) => {\r\n const facetGroup = this.detailForm.get('facet');\r\n const updateOperations: Array<Observable<any>> = [];\r\n\r\n if (facetGroup && facetGroup.dirty) {\r\n const newFacet = this.getUpdatedFacet(\r\n facet,\r\n facetGroup as FormGroup,\r\n languageCode,\r\n ) as UpdateFacetInput;\r\n if (newFacet) {\r\n updateOperations.push(this.dataService.facet.updateFacet(newFacet));\r\n }\r\n }\r\n const valuesArray = this.detailForm.get('values');\r\n if (valuesArray && valuesArray.dirty) {\r\n const createdValues = this.getCreatedFacetValues(\r\n facet,\r\n valuesArray as FormArray,\r\n languageCode,\r\n );\r\n if (createdValues.length) {\r\n updateOperations.push(\r\n this.dataService.facet\r\n .createFacetValues(createdValues)\r\n .pipe(switchMap(() => this.dataService.facet.getFacet(this.id).single$)),\r\n );\r\n }\r\n const updatedValues = this.getUpdatedFacetValues(\r\n facet,\r\n valuesArray as FormArray,\r\n languageCode,\r\n );\r\n if (updatedValues.length) {\r\n updateOperations.push(this.dataService.facet.updateFacetValues(updatedValues));\r\n }\r\n }\r\n\r\n return forkJoin(updateOperations);\r\n }),\r\n switchMap(() => this.dataService.facet.getAllFacets().single$),\r\n )\r\n .subscribe(\r\n () => {\r\n this.detailForm.markAsPristine();\r\n this.changeDetector.markForCheck();\r\n this.notificationService.success(_('common.notify-update-success'), { entity: 'Facet' });\r\n },\r\n err => {\r\n this.notificationService.error(_('common.notify-update-error'), {\r\n entity: 'Facet',\r\n });\r\n },\r\n );\r\n }\r\n\r\n deleteFacetValue(facetValueId: string | undefined, index: number) {\r\n if (!facetValueId) {\r\n // deleting a newly-added (not persisted) FacetValue\r\n const valuesFormArray = this.detailForm.get('values') as FormArray | null;\r\n if (valuesFormArray) {\r\n valuesFormArray.removeAt(index);\r\n }\r\n this.values.splice(index, 1);\r\n return;\r\n }\r\n this.showModalAndDelete(facetValueId)\r\n .pipe(\r\n switchMap(response => {\r\n if (response.result === DeletionResult.DELETED) {\r\n return [true];\r\n } else {\r\n return this.showModalAndDelete(facetValueId, response.message || '').pipe(\r\n map(r => r.result === DeletionResult.DELETED),\r\n );\r\n }\r\n }),\r\n switchMap(deleted => (deleted ? this.dataService.facet.getFacet(this.id).single$ : [])),\r\n )\r\n .subscribe(\r\n () => {\r\n const valuesFormArray = this.detailForm.get('values') as FormArray | null;\r\n if (valuesFormArray) {\r\n valuesFormArray.removeAt(index);\r\n }\r\n this.notificationService.success(_('common.notify-delete-success'), {\r\n entity: 'FacetValue',\r\n });\r\n },\r\n err => {\r\n this.notificationService.error(_('common.notify-delete-error'), {\r\n entity: 'FacetValue',\r\n });\r\n },\r\n );\r\n }\r\n\r\n private showModalAndDelete(facetValueId: string, message?: string) {\r\n return this.modalService\r\n .dialog({\r\n title: _('catalog.confirm-delete-facet-value'),\r\n body: message,\r\n buttons: [\r\n { type: 'secondary', label: _('common.cancel') },\r\n { type: 'danger', label: _('common.delete'), returnValue: true },\r\n ],\r\n })\r\n .pipe(\r\n switchMap(result =>\r\n result ? this.dataService.facet.deleteFacetValues([facetValueId], !!message) : EMPTY,\r\n ),\r\n map(result => result.deleteFacetValues[0]),\r\n );\r\n }\r\n\r\n /**\r\n * Sets the values of the form on changes to the facet or current language.\r\n */\r\n protected setFormValues(facet: FacetWithValuesFragment, languageCode: LanguageCode) {\r\n const currentTranslation = findTranslation(facet, languageCode);\r\n\r\n this.detailForm.patchValue({\r\n facet: {\r\n code: facet.code,\r\n visible: !facet.isPrivate,\r\n name: currentTranslation?.name ?? '',\r\n },\r\n });\r\n\r\n if (this.customFields.length) {\r\n const customFieldsGroup = this.detailForm.get(['facet', 'customFields']) as FormGroup;\r\n this.setCustomFieldFormValues(\r\n this.customFields,\r\n this.detailForm.get(['facet', 'customFields']),\r\n facet,\r\n currentTranslation,\r\n );\r\n }\r\n\r\n const currentValuesFormArray = this.detailForm.get('values') as FormArray;\r\n this.values = [...facet.values];\r\n facet.values.forEach(value => {\r\n const valueTranslation = findTranslation(value, languageCode);\r\n const group = {\r\n id: value.id,\r\n code: value.code,\r\n name: valueTranslation ? valueTranslation.name : '',\r\n };\r\n let valueControl = currentValuesFormArray.controls.find(\r\n control => control.value.id === value.id,\r\n ) as FormGroup | undefined;\r\n if (valueControl) {\r\n valueControl.get('id')?.setValue(group.id);\r\n valueControl.get('code')?.setValue(group.code);\r\n valueControl.get('name')?.setValue(group.name);\r\n } else {\r\n valueControl = this.formBuilder.group(group);\r\n currentValuesFormArray.push(valueControl);\r\n }\r\n if (this.customValueFields.length) {\r\n let customValueFieldsGroup = valueControl.get(['customFields']) as FormGroup | undefined;\r\n if (!customValueFieldsGroup) {\r\n customValueFieldsGroup = new FormGroup({});\r\n valueControl.addControl('customFields', customValueFieldsGroup);\r\n }\r\n\r\n if (customValueFieldsGroup) {\r\n for (const fieldDef of this.customValueFields) {\r\n const key = fieldDef.name;\r\n const fieldValue =\r\n fieldDef.type === 'localeString'\r\n ? (valueTranslation as any | undefined)?.customFields?.[key]\r\n : (value as any).customFields[key];\r\n const control = customValueFieldsGroup.get(key);\r\n if (control) {\r\n control.setValue(fieldValue);\r\n } else {\r\n customValueFieldsGroup.addControl(key, new FormControl(fieldValue));\r\n }\r\n }\r\n }\r\n }\r\n });\r\n }\r\n\r\n /**\r\n * Given a facet and the value of the detailForm, this method creates an updated copy of the facet which\r\n * can then be persisted to the API.\r\n */\r\n private getUpdatedFacet(\r\n facet: FacetWithValuesFragment,\r\n facetFormGroup: FormGroup,\r\n languageCode: LanguageCode,\r\n ): CreateFacetInput | UpdateFacetInput {\r\n const input = createUpdatedTranslatable({\r\n translatable: facet,\r\n updatedFields: facetFormGroup.value,\r\n customFieldConfig: this.customFields,\r\n languageCode,\r\n defaultTranslation: {\r\n languageCode,\r\n name: facet.name || '',\r\n },\r\n });\r\n input.isPrivate = !facetFormGroup.value.visible;\r\n return input;\r\n }\r\n\r\n /**\r\n * Given an array of facet values and the values from the detailForm, this method creates a new array\r\n * which can be persisted to the API via a createFacetValues mutation.\r\n */\r\n private getCreatedFacetValues(\r\n facet: FacetWithValuesFragment,\r\n valuesFormArray: FormArray,\r\n languageCode: LanguageCode,\r\n ): CreateFacetValueInput[] {\r\n return valuesFormArray.controls\r\n .filter(c => !c.value.id)\r\n .map(c => c.value)\r\n .map(value =>\r\n createUpdatedTranslatable({\r\n translatable: { ...value, translations: [] as any },\r\n updatedFields: value,\r\n customFieldConfig: this.customValueFields,\r\n languageCode,\r\n defaultTranslation: {\r\n languageCode,\r\n name: '',\r\n },\r\n }),\r\n )\r\n .map(input => ({\r\n facetId: facet.id,\r\n ...input,\r\n }));\r\n }\r\n\r\n /**\r\n * Given an array of facet values and the values from the detailForm, this method creates a new array\r\n * which can be persisted to the API via an updateFacetValues mutation.\r\n */\r\n private getUpdatedFacetValues(\r\n facet: FacetWithValuesFragment,\r\n valuesFormArray: FormArray,\r\n languageCode: LanguageCode,\r\n ): UpdateFacetValueInput[] {\r\n const dirtyValues = facet.values.filter((v, i) => {\r\n const formRow = valuesFormArray.get(i.toString());\r\n return formRow && formRow.dirty && formRow.value.id;\r\n });\r\n const dirtyValueValues = valuesFormArray.controls\r\n .filter(c => c.dirty && c.value.id)\r\n .map(c => c.value);\r\n\r\n if (dirtyValues.length !== dirtyValueValues.length) {\r\n throw new Error(_(`error.facet-value-form-values-do-not-match`));\r\n }\r\n return dirtyValues\r\n .map((value, i) => {\r\n return createUpdatedTranslatable({\r\n translatable: value,\r\n updatedFields: dirtyValueValues[i],\r\n customFieldConfig: this.customValueFields,\r\n languageCode,\r\n defaultTranslation: {\r\n languageCode,\r\n name: '',\r\n },\r\n });\r\n })\r\n .filter(notNullOrUndefined);\r\n }\r\n}\r\n","<vdr-action-bar>\r\n <vdr-ab-left>\r\n <div class=\"\">\r\n <input\r\n type=\"text\"\r\n name=\"searchTerm\"\r\n [formControl]=\"filterTermControl\"\r\n [placeholder]=\"'catalog.filter-by-name' | translate\"\r\n class=\"clr-input search-input\"\r\n />\r\n <div>\r\n <vdr-language-selector\r\n [availableLanguageCodes]=\"availableLanguages$ | async\"\r\n [currentLanguageCode]=\"contentLanguage$ | async\"\r\n (languageCodeChange)=\"setLanguage($event)\"\r\n ></vdr-language-selector>\r\n </div>\r\n </div>\r\n </vdr-ab-left>\r\n <vdr-ab-right>\r\n <vdr-action-bar-items locationId=\"facet-list\"></vdr-action-bar-items>\r\n <a\r\n class=\"btn btn-primary\"\r\n *vdrIfPermissions=\"['CreateCatalog', 'CreateFacet']\"\r\n [routerLink]=\"['./create']\"\r\n >\r\n <clr-icon shape=\"plus\"></clr-icon>\r\n {{ 'catalog.create-new-facet' | translate }}\r\n </a>\r\n </vdr-ab-right>\r\n</vdr-action-bar>\r\n\r\n<vdr-data-table\r\n [items]=\"items$ | async\"\r\n [itemsPerPage]=\"itemsPerPage$ | async\"\r\n [totalItems]=\"totalItems$ | async\"\r\n [currentPage]=\"currentPage$ | async\"\r\n (pageChange)=\"setPageNumber($event)\"\r\n (itemsPerPageChange)=\"setItemsPerPage($event)\"\r\n [selectionManager]=\"selectionManager\"\r\n>\r\n <vdr-bulk-action-menu\r\n locationId=\"facet-list\"\r\n [hostComponent]=\"this\"\r\n [selectionManager]=\"selectionManager\"\r\n ></vdr-bulk-action-menu>\r\n <vdr-dt-column>{{ 'common.code' | translate }}</vdr-dt-column>\r\n <vdr-dt-column>{{ 'common.name' | translate }}</vdr-dt-column>\r\n <vdr-dt-column [expand]=\"true\">{{ 'catalog.values' | translate }}</vdr-dt-column>\r\n <vdr-dt-column>{{ 'catalog.visibility' | translate }}</vdr-dt-column>\r\n <vdr-dt-column></vdr-dt-column>\r\n <vdr-dt-column></vdr-dt-column>\r\n <ng-template let-facet=\"item\">\r\n <td class=\"left align-middle\" [class.private]=\"facet.isPrivate\">{{ facet.code }}</td>\r\n <td class=\"left align-middle\" [class.private]=\"facet.isPrivate\">{{ facet.name }}</td>\r\n <td class=\"left align-middle\" [class.private]=\"facet.isPrivate\">\r\n <vdr-facet-value-chip\r\n *ngFor=\"let value of facet.values | slice: 0:displayLimit[facet.id] || 3\"\r\n [facetValue]=\"value\"\r\n [removable]=\"false\"\r\n [displayFacetName]=\"false\"\r\n ></vdr-facet-value-chip>\r\n <button\r\n class=\"btn btn-sm btn-secondary btn-icon\"\r\n *ngIf=\"facet.values.length > initialLimit\"\r\n (click)=\"toggleDisplayLimit(facet)\"\r\n >\r\n <ng-container *ngIf=\"(displayLimit[facet.id] || 0) < facet.values.length; else collapse\">\r\n <clr-icon shape=\"plus\"></clr-icon>\r\n {{ facet.values.length - initialLimit }}\r\n </ng-container>\r\n <ng-template #collapse>\r\n <clr-icon shape=\"minus\"></clr-icon>\r\n </ng-template>\r\n </button>\r\n </td>\r\n <td class=\"left align-middle\" [class.private]=\"facet.isPrivate\">\r\n <vdr-chip>\r\n <ng-container *ngIf=\"!facet.isPrivate; else private\">{{\r\n 'catalog.public' | translate\r\n }}</ng-container>\r\n <ng-template #private>{{ 'catalog.private' | translate }}</ng-template>\r\n </vdr-chip>\r\n </td>\r\n <td class=\"right align-middle\" [class.private]=\"facet.isPrivate\">\r\n <vdr-table-row-action\r\n iconShape=\"edit\"\r\n [label]=\"'common.edit' | translate\"\r\n [linkTo]=\"['./', facet.id]\"\r\n ></vdr-table-row-action>\r\n </td>\r\n <td class=\"right align-middle\" [class.private]=\"facet.isPrivate\">\r\n <vdr-dropdown>\r\n <button type=\"button\" class=\"btn btn-link btn-sm\" vdrDropdownTrigger>\r\n {{ 'common.actions' | translate }}\r\n <clr-icon shape=\"caret down\"></clr-icon>\r\n </button>\r\n <vdr-dropdown-menu vdrPosition=\"bottom-right\">\r\n <button\r\n type=\"button\"\r\n class=\"delete-button\"\r\n (click)=\"deleteFacet(facet.id)\"\r\n [disabled]=\"!(['DeleteCatalog', 'DeleteFacet'] | hasPermission)\"\r\n vdrDropdownItem\r\n >\r\n <clr-icon shape=\"trash\" class=\"is-danger\"></clr-icon>\r\n {{ 'common.delete' | translate }}\r\n </button>\r\n </vdr-dropdown-menu>\r\n </vdr-dropdown>\r\n </td>\r\n </ng-template>\r\n</vdr-data-table>\r\n","import { Component, OnInit } from '@angular/core';\r\nimport { FormControl } from '@angular/forms';\r\nimport { ActivatedRoute, Router } from '@angular/router';\r\nimport { marker as _ } from '@biesbjerg/ngx-translate-extract-marker';\r\nimport {\r\n BaseListComponent,\r\n DataService,\r\n DeletionResult,\r\n GetFacetListQuery,\r\n ItemOf,\r\n LanguageCode,\r\n ModalService,\r\n NotificationService,\r\n SelectionManager,\r\n ServerConfigService,\r\n} from '@vendure/admin-ui/core';\r\nimport { SortOrder } from '@vendure/common/lib/generated-shop-types';\r\nimport { EMPTY, Observable } from 'rxjs';\r\nimport { debounceTime, filter, map, switchMap, takeUntil, tap } from 'rxjs/operators';\r\n\r\n@Component({\r\n selector: 'vdr-facet-list',\r\n templateUrl: './facet-list.component.html',\r\n styleUrls: ['./facet-list.component.scss'],\r\n})\r\nexport class FacetListComponent\r\n extends BaseListComponent<GetFacetListQuery, ItemOf<GetFacetListQuery, 'facets'>>\r\n implements OnInit\r\n{\r\n filterTermControl = new FormControl('');\r\n availableLanguages$: Observable<LanguageCode[]>;\r\n contentLanguage$: Observable<LanguageCode>;\r\n readonly initialLimit = 3;\r\n displayLimit: { [id: string]: number } = {};\r\n selectionManager: SelectionManager<ItemOf<GetFacetListQuery, 'facets'>>;\r\n\r\n constructor(\r\n private dataService: DataService,\r\n private modalService: ModalService,\r\n private notificationService: NotificationService,\r\n private serverConfigService: ServerConfigService,\r\n router: Router,\r\n route: ActivatedRoute,\r\n ) {\r\n super(router, route);\r\n super.setQueryFn(\r\n (...args: any[]) => this.dataService.facet.getFacets(...args).refetchOnChannelChange(),\r\n data => data.facets,\r\n (skip, take) => ({\r\n options: {\r\n skip,\r\n take,\r\n filter: {\r\n name: {\r\n contains: this.filterTermControl.value,\r\n },\r\n },\r\n sort: {\r\n createdAt: SortOrder.DESC,\r\n },\r\n },\r\n }),\r\n );\r\n this.selectionManager = new SelectionManager({\r\n multiSelect: true,\r\n itemsAreEqual: (a, b) => a.id === b.id,\r\n additiveMode: true,\r\n });\r\n }\r\n\r\n ngOnInit() {\r\n super.ngOnInit();\r\n this.availableLanguages$ = this.serverConfigService.getAvailableLanguages();\r\n this.contentLanguage$ = this.dataService.client\r\n .uiState()\r\n .mapStream(({ uiState }) => uiState.contentLanguage)\r\n .pipe(tap(() => this.refresh()));\r\n this.filterTermControl.valueChanges\r\n .pipe(\r\n filter(value => 2 <= value.length || value.length === 0),\r\n debounceTime(250),\r\n takeUntil(this.destroy$),\r\n )\r\n .subscribe(() => this.refresh());\r\n }\r\n\r\n toggleDisplayLimit(facet: ItemOf<GetFacetListQuery, 'facets'>) {\r\n if (this.displayLimit[facet.id] === facet.values.length) {\r\n this.displayLimit[facet.id] = this.initialLimit;\r\n } else {\r\n this.displayLimit[facet.id] = facet.values.length;\r\n }\r\n }\r\n\r\n deleteFacet(facetValueId: string) {\r\n this.showModalAndDelete(facetValueId)\r\n .pipe(\r\n switchMap(response => {\r\n if (response.result === DeletionResult.DELETED) {\r\n return [true];\r\n } else {\r\n return this.showModalAndDelete(facetValueId, response.message || '').pipe(\r\n map(r => r.result === DeletionResult.DELETED),\r\n );\r\n }\r\n }),\r\n // Refresh the cached facets to reflect the changes\r\n switchMap(() => this.dataService.facet.getAllFacets().single$),\r\n )\r\n .subscribe(\r\n () => {\r\n this.notificationService.success(_('common.notify-delete-success'), {\r\n entity: 'FacetValue',\r\n });\r\n this.refresh();\r\n },\r\n err => {\r\n this.notificationService.error(_('common.notify-delete-error'), {\r\n entity: 'FacetValue',\r\n });\r\n },\r\n );\r\n }\r\n\r\n setLanguage(code: LanguageCode) {\r\n this.dataService.client.setContentLanguage(code).subscribe();\r\n }\r\n\r\n private showModalAndDelete(facetId: string, message?: string) {\r\n return this.modalService\r\n .dialog({\r\n title: _('catalog.confirm-delete-facet'),\r\n body: message,\r\n buttons: [\r\n { type: 'secondary', label: _('common.cancel') },\r\n {\r\n type: 'danger',\r\n label: message ? _('common.force-delete') : _('common.delete'),\r\n returnValue: true,\r\n },\r\n ],\r\n })\r\n .pipe(\r\n switchMap(res => (res ? this.dataService.facet.deleteFacet(facetId, !!message) : EMPTY)),\r\n map(res => res.deleteFacet),\r\n );\r\n }\r\n}\r\n","<ng-template vdrDialogTitle>{{ 'catalog.add-facets' | translate }}</ng-template>\r\n\r\n<vdr-facet-value-selector\r\n (selectedValuesChange)=\"selectedValues = $event\"\r\n></vdr-facet-value-selector>\r\n\r\n<ng-template vdrDialogButtons>\r\n <button type=\"button\" class=\"btn\" (click)=\"cancel()\">{{ 'common.cancel' | translate }}</button>\r\n <button\r\n type=\"submit\"\r\n (click)=\"selectValues()\"\r\n [disabled]=\"selectedValues.length === 0\"\r\n class=\"btn btn-primary\"\r\n >\r\n {{ 'catalog.add-facets' | translate }}\r\n </button>\r\n</ng-template>\r\n","import {\r\n AfterViewInit,\r\n ChangeDetectionStrategy,\r\n ChangeDetectorRef,\r\n Component,\r\n ViewChild,\r\n} from '@angular/core';\r\nimport {\r\n Dialog,\r\n FacetValue,\r\n FacetValueSelectorComponent,\r\n FacetWithValuesFragment,\r\n} from '@vendure/admin-ui/core';\r\n\r\n@Component({\r\n selector: 'vdr-apply-facet-dialog',\r\n templateUrl: './apply-facet-dialog.component.html',\r\n styleUrls: ['./apply-facet-dialog.component.scss'],\r\n changeDetection: ChangeDetectionStrategy.OnPush,\r\n})\r\nexport class ApplyFacetDialogComponent implements Dialog<FacetValue[]>, AfterViewInit {\r\n @ViewChild(FacetValueSelectorComponent) private selector: FacetValueSelectorComponent;\r\n resolveWith: (result?: FacetValue[]) => void;\r\n selectedValues: FacetValue[] = [];\r\n // Provided by caller\r\n facets: FacetWithValuesFragment[];\r\n\r\n constructor(private changeDetector: ChangeDetectorRef) {}\r\n\r\n ngAfterViewInit() {\r\n setTimeout(() => this.selector.focus(), 0);\r\n }\r\n\r\n selectValues() {\r\n this.resolveWith(this.selectedValues);\r\n }\r\n\r\n cancel() {\r\n this.resolveWith();\r\n }\r\n}\r\n","<ng-template vdrDialogTitle>\r\n <ng-container *ngIf=\"isProductVariantMode; else productModeTitle\">{{\r\n 'catalog.assign-variants-to-channel' | translate\r\n }}</ng-container>\r\n <ng-template #productModeTitle>{{ 'catalog.assign-products-to-channel' | translate }}</ng-template>\r\n</ng-template>\r\n\r\n<div class=\"flex\">\r\n <clr-input-container>\r\n <label>{{ 'common.channel' | translate }}</label>\r\n <vdr-channel-assignment-control\r\n clrInput\r\n [multiple]=\"false\"\r\n [includeDefaultChannel]=\"false\"\r\n [disableChannelIds]=\"currentChannelIds\"\r\n [formControl]=\"selectedChannelIdControl\"\r\n ></vdr-channel-assignment-control>\r\n </clr-input-container>\r\n <div class=\"flex-spacer\"></div>\r\n <clr-input-container>\r\n <label>{{ 'catalog.price-conversion-factor' | translate }}</label>\r\n <input clrInput type=\"number\" min=\"0\" max=\"99999\" [formControl]=\"priceFactorControl\" />\r\n </clr-input-container>\r\n</div>\r\n\r\n<div class=\"channel-price-preview\">\r\n <label class=\"clr-control-label\">{{ 'catalog.channel-price-preview' | translate }}</label>\r\n <table class=\"table\">\r\n <thead>\r\n <tr>\r\n <th>{{ 'common.name' | translate }}</th>\r\n <th>\r\n {{\r\n 'catalog.price-in-channel'\r\n | translate: { channel: currentChannel?.code | channelCodeToLabel | translate }\r\n }}\r\n </th>\r\n <th>\r\n <ng-template [ngIf]=\"selectedChannel\" [ngIfElse]=\"noSelection\">\r\n {{ 'catalog.price-in-channel' | translate: { channel: selectedChannel?.code } }}\r\n </ng-template>\r\n <ng-template #noSelection>\r\n {{ 'catalog.no-channel-selected' | translate }}\r\n </ng-template>\r\n </th>\r\n </tr>\r\n </thead>\r\n <tbody>\r\n <tr *ngFor=\"let row of variantsPreview$ | async\">\r\n <td>{{ row.name }}</td>\r\n <td>{{ row.price | localeCurrency: currentChannel?.currencyCode }}</td>\r\n <td>\r\n <ng-template [ngIf]=\"selectedChannel\" [ngIfElse]=\"noChannelSelected\">\r\n {{ row.pricePreview | localeCurrency: selectedChannel?.currencyCode }}\r\n </ng-template>\r\n <ng-template #noChannelSelected> - </ng-template>\r\n </td>\r\n </tr>\r\n </tbody>\r\n </table>\r\n</div>\r\n\r\n<ng-template vdrDialogButtons>\r\n <button type=\"button\" class=\"btn\" (click)=\"cancel()\">{{ 'common.cancel' | translate }}</button>\r\n <button type=\"submit\" (click)=\"assign()\" [disabled]=\"!selectedChannel\" class=\"btn btn-primary\">\r\n <ng-template [ngIf]=\"selectedChannel\" [ngIfElse]=\"noSelection\">\r\n {{ 'catalog.assign-to-named-channel' | translate: { channelCode: selectedChannel?.code } }}\r\n </ng-template>\r\n <ng-template #noSelection>\r\n {{ 'catalog.no-channel-selected' | translate }}\r\n </ng-template>\r\n </button>\r\n</ng-template>\r\n","import { ChangeDetectionStrategy, Component, OnInit } from '@angular/core';\r\nimport { FormControl } from '@angular/forms';\r\nimport { marker as _ } from '@biesbjerg/ngx-translate-extract-marker';\r\nimport {\r\n DataService,\r\n Dialog,\r\n GetChannelsQuery,\r\n NotificationService,\r\n ProductVariantFragment,\r\n} from '@vendure/admin-ui/core';\r\nimport { combineLatest, from, Observable } from 'rxjs';\r\nimport { map, startWith } from 'rxjs/operators';\r\n\r\ntype Channel = GetChannelsQuery['channels'][number];\r\n\r\n@Component({\r\n selector: 'vdr-assign-products-to-channel-dialog',\r\n templateUrl: './assign-products-to-channel-dialog.component.html',\r\n styleUrls: ['./assign-products-to-channel-dialog.component.scss'],\r\n changeDetection: ChangeDetectionStrategy.OnPush,\r\n})\r\nexport class AssignProductsToChannelDialogComponent implements OnInit, Dialog<any> {\r\n selectedChannel: Channel | null | undefined;\r\n currentChannel: Channel;\r\n availableChannels: Channel[];\r\n resolveWith: (result?: any) => void;\r\n variantsPreview$: Observable<Array<{ id: string; name: string; price: number; pricePreview: number }>>;\r\n priceFactorControl = new FormControl(1);\r\n selectedChannelIdControl = new FormControl();\r\n\r\n // assigned by ModalService.fromComponent() call\r\n productIds: string[];\r\n productVariantIds: string[] | undefined;\r\n currentChannelIds: string[];\r\n\r\n get isProductVariantMode(): boolean {\r\n return this.productVariantIds != null;\r\n }\r\n\r\n constructor(private dataService: DataService, private notificationService: NotificationService) {}\r\n\r\n ngOnInit() {\r\n const activeChannelId$ = this.dataService.client\r\n .userStatus()\r\n .mapSingle(({ userStatus }) => userStatus.activeChannelId);\r\n const allChannels$ = this.dataService.settings.getChannels().mapSingle(data => data.channels);\r\n\r\n combineLatest(activeChannelId$, allChannels$).subscribe(([activeChannelId, channels]) => {\r\n // tslint:disable-next-line:no-non-null-assertion\r\n this.currentChannel = channels.find(c => c.id === activeChannelId)!;\r\n this.availableChannels = channels;\r\n });\r\n\r\n this.selectedChannelIdControl.valueChanges.subscribe(ids => {\r\n this.selectChannel(ids);\r\n });\r\n\r\n this.variantsPreview$ = combineLatest(\r\n from(this.getTopVariants(10)),\r\n this.priceFactorControl.valueChanges.pipe(startWith(1)),\r\n ).pipe(\r\n map(([variants, factor]) => {\r\n return variants.map(v => ({\r\n id: v.id,\r\n name: v.name,\r\n price: v.price,\r\n pricePreview: v.price * +factor,\r\n }));\r\n }),\r\n );\r\n }\r\n\r\n selectChannel(channelIds: string[]) {\r\n this.selectedChannel = this.availableChannels.find(c => c.id === channelIds[0]);\r\n }\r\n\r\n assign() {\r\n const selectedChannel = this.selectedChannel;\r\n if (selectedChannel) {\r\n if (!this.isProductVariantMode) {\r\n this.dataService.product\r\n .assignProductsToChannel({\r\n channelId: selectedChannel.id,\r\n productIds: this.productIds,\r\n priceFactor: +this.priceFactorControl.value,\r\n })\r\n .subscribe(() => {\r\n this.notificationService.success(_('catalog.assign-product-to-channel-success'), {\r\n channel: selectedChannel.code,\r\n count: this.productIds.length,\r\n });\r\n this.resolveWith(true);\r\n });\r\n } else if (this.productVariantIds) {\r\n this.dataService.product\r\n .assignVariantsToChannel({\r\n channelId: selectedChannel.id,\r\n productVariantIds: this.productVariantIds,\r\n priceFactor: +this.priceFactorControl.value,\r\n })\r\n .subscribe(() => {\r\n this.notificationService.success(_('catalog.assign-variant-to-channel-success'), {\r\n channel: selectedChannel.code,\r\n // tslint:disable-next-line:no-non-null-assertion\r\n count: this.productVariantIds!.length,\r\n });\r\n this.resolveWith(true);\r\n });\r\n }\r\n }\r\n }\r\n\r\n cancel() {\r\n this.resolveWith();\r\n }\r\n\r\n private async getTopVariants(take: number): Promise<ProductVariantFragment[]> {\r\n const variants: ProductVariantFragment[] = [];\r\n\r\n for (let i = 0; i < this.productIds.length && variants.length < take; i++) {\r\n const productVariants = await this.dataService.product\r\n .getProduct(this.productIds[i], { take: this.isProductVariantMode ? undefined : take })\r\n .mapSingle(({ product }) => {\r\n const _variants = product ? product.variantList.items : [];\r\n return _variants.filter(v =>\r\n this.isProductVariantMode ? this.productVariantIds?.includes(v.id) : true,\r\n );\r\n })\r\n .toPromise();\r\n variants.push(...(productVariants || []));\r\n }\r\n return variants.slice(0, take);\r\n }\r\n}\r\n","/**\r\n * @description\r\n * Like String.prototype.replace(), but replaces the last instance\r\n * rather than the first.\r\n */\r\nexport function replaceLast(target: string | undefined | null, search: string, replace: string): string {\r\n if (!target) {\r\n return '';\r\n }\r\n const lastIndex = target.lastIndexOf(search);\r\n if (lastIndex === -1) {\r\n return target;\r\n }\r\n const head = target.substr(0, lastIndex);\r\n const tail = target.substr(lastIndex).replace(search, replace);\r\n return head + tail;\r\n}\r\n","import { Injectable } from '@angular/core';\r\nimport {\r\n CreateProductInput,\r\n CreateProductVariantInput,\r\n DataService,\r\n DeletionResult,\r\n FacetWithValuesFragment,\r\n findTranslation,\r\n GetProductWithVariantsQuery,\r\n LanguageCode,\r\n UpdateProductInput,\r\n UpdateProductMutation,\r\n UpdateProductOptionInput,\r\n UpdateProductVariantInput,\r\n UpdateProductVariantsMutation,\r\n} from '@vendure/admin-ui/core';\r\nimport { normalizeString } from '@vendure/common/lib/normalize-string';\r\nimport { notNullOrUndefined } from '@vendure/common/lib/shared-utils';\r\nimport { forkJoin, Observable, of, throwError } from 'rxjs';\r\nimport { map, mergeMap, shareReplay, switchMap } from 'rxjs/operators';\r\n\r\nimport { CreateProductVariantsConfig } from '../../components/generate-product-variants/generate-product-variants.component';\r\n\r\nimport { replaceLast } from './replace-last';\r\n\r\n/**\r\n * Handles the logic for making the API calls to perform CRUD operations on a Product and its related\r\n * entities. This logic was extracted out of the component because it became too large and hard to follow.\r\n */\r\n@Injectable({\r\n providedIn: 'root',\r\n})\r\nexport class ProductDetailService {\r\n constructor(private dataService: DataService) {}\r\n\r\n getTaxCategories() {\r\n return this.dataService.settings\r\n .getTaxCategories()\r\n .mapSingle(data => data.taxCategories)\r\n .pipe(shareReplay(1));\r\n }\r\n\r\n createProductWithVariants(\r\n input: CreateProductInput,\r\n createVariantsConfig: CreateProductVariantsConfig,\r\n languageCode: LanguageCode,\r\n ) {\r\n const createProduct$ = this.dataService.product.createProduct(input);\r\n const nonEmptyOptionGroups = createVariantsConfig.groups.filter(g => 0 < g.values.length);\r\n const createOptionGroups$ = this.createProductOptionGroups(nonEmptyOptionGroups, languageCode);\r\n\r\n return forkJoin(createProduct$, createOptionGroups$).pipe(\r\n mergeMap(([{ createProduct }, optionGroups]) => {\r\n const addOptionsToProduct$ = optionGroups.length\r\n ? forkJoin(\r\n optionGroups.map(optionGroup => {\r\n return this.dataService.product.addOptionGroupToProduct({\r\n productId: createProduct.id,\r\n optionGroupId: optionGroup.id,\r\n });\r\n }),\r\n )\r\n : of([]);\r\n return addOptionsToProduct$.pipe(\r\n map(() => {\r\n return { createProduct, optionGroups };\r\n }),\r\n );\r\n }),\r\n mergeMap(({ createProduct, optionGroups }) => {\r\n const variants = createVariantsConfig.variants.map(v => {\r\n const optionIds = optionGroups.length\r\n ? v.optionValues.map((optionName, index) => {\r\n const option = optionGroups[index].options.find(o => o.name === optionName);\r\n if (!option) {\r\n throw new Error(\r\n `Could not find a matching ProductOption \"${optionName}\" when creating variant`,\r\n );\r\n }\r\n return option.id;\r\n })\r\n : [];\r\n return {\r\n ...v,\r\n optionIds,\r\n };\r\n });\r\n const options = optionGroups.map(og => og.options).reduce((flat, o) => [...flat, ...o], []);\r\n return this.createProductVariants(createProduct, variants, options, languageCode);\r\n }),\r\n );\r\n }\r\n\r\n createProductOptionGroups(groups: Array<{ name: string; values: string[] }>, languageCode: LanguageCode) {\r\n return groups.length\r\n ? forkJoin(\r\n groups.map(c => {\r\n return this.dataService.product\r\n .createProductOptionGroups({\r\n code: normalizeString(c.name, '-'),\r\n translations: [{ languageCode, name: c.name }],\r\n options: c.values.map(v => ({\r\n code: normalizeString(v, '-'),\r\n translations: [{ languageCode, name: v }],\r\n })),\r\n })\r\n .pipe(map(data => data.createProductOptionGroup));\r\n }),\r\n )\r\n : of([]);\r\n }\r\n\r\n createProductVariants(\r\n product: { name: string; id: string },\r\n variantData: Array<{ price: number; sku: string; stock: number; optionIds: string[] }>,\r\n options: Array<{ id: string; name: string }>,\r\n languageCode: LanguageCode,\r\n ) {\r\n const variants: CreateProductVariantInput[] = variantData.map(v => {\r\n const name = options.length\r\n ? `${product.name} ${v.optionIds\r\n .map(id => options.find(o => o.id === id))\r\n .filter(notNullOrUndefined)\r\n .map(o => o.name)\r\n .join(' ')}`\r\n : product.name;\r\n return {\r\n productId: product.id,\r\n price: v.price,\r\n sku: v.sku,\r\n stockOnHand: v.stock,\r\n translations: [\r\n {\r\n languageCode,\r\n name,\r\n },\r\n ],\r\n optionIds: v.optionIds,\r\n };\r\n });\r\n return this.dataService.product.createProductVariants(variants).pipe(\r\n map(({ createProductVariants }) => ({\r\n createProductVariants,\r\n productId: product.id,\r\n })),\r\n );\r\n }\r\n\r\n updateProduct(updateOptions: {\r\n product: NonNullable<GetProductWithVariantsQuery['product']>;\r\n languageCode: LanguageCode;\r\n autoUpdate: boolean;\r\n productInput?: UpdateProductInput;\r\n variantsInput?: UpdateProductVariantInput[];\r\n }) {\r\n const { product, languageCode, autoUpdate, productInput, variantsInput } = updateOptions;\r\n const updateOperations: Array<Observable<UpdateProductMutation | UpdateProductVariantsMutation>> = [];\r\n const updateVariantsInput = variantsInput || [];\r\n\r\n const variants$ = autoUpdate\r\n ? this.dataService.product\r\n .getProductVariants({}, product.id)\r\n .mapSingle(({ productVariants }) => productVariants.items)\r\n : of([]);\r\n\r\n return variants$.pipe(\r\n mergeMap(variants => {\r\n if (productInput) {\r\n updateOperations.push(this.dataService.product.updateProduct(productInput));\r\n const productOldName = findTranslation(product, languageCode)?.name ?? '';\r\n const productNewName = findTranslation(productInput, languageCode)?.name;\r\n if (productNewName && productOldName !== productNewName && autoUpdate) {\r\n for (const variant of variants) {\r\n const currentVariantName = findTranslation(variant, languageCode)?.name || '';\r\n let variantInput: UpdateProductVariantInput;\r\n const existingVariantInput = updateVariantsInput.find(i => i.id === variant.id);\r\n if (existingVariantInput) {\r\n variantInput = existingVariantInput;\r\n } else {\r\n variantInput = {\r\n id: variant.id,\r\n translations: [{ languageCode, name: currentVariantName }],\r\n };\r\n updateVariantsInput.push(variantInput);\r\n }\r\n const variantTranslation = findTranslation(variantInput, languageCode);\r\n if (variantTranslation) {\r\n if (variantTranslation.name) {\r\n variantTranslation.name = replaceLast(\r\n variantTranslation.name,\r\n productOldName,\r\n productNewName,\r\n );\r\n } else {\r\n // The variant translation was falsy, which occurs\r\n // when defining the product name for a new translation\r\n // language that had not yet been defined.\r\n variantTranslation.name = [\r\n productNewName,\r\n ...variant.options.map(o => o.name),\r\n ].join(' ');\r\n }\r\n }\r\n }\r\n }\r\n }\r\n if (updateVariantsInput.length) {\r\n updateOperations.push(\r\n this.dataService.product.updateProductVariants(updateVariantsInput),\r\n );\r\n }\r\n return forkJoin(updateOperations);\r\n }),\r\n );\r\n }\r\n\r\n updateProductOption(\r\n input: UpdateProductOptionInput & { autoUpdate: boolean },\r\n product: NonNullable<GetProductWithVariantsQuery['product']>,\r\n languageCode: LanguageCode,\r\n ) {\r\n const variants$ = input.autoUpdate\r\n ? this.dataService.product\r\n .getProductVariants({}, product.id)\r\n .mapSingle(({ productVariants }) => productVariants.items)\r\n : of([]);\r\n\r\n return variants$.pipe(\r\n mergeMap(variants => {\r\n let updateProductVariantNames$: Observable<any> = of([]);\r\n if (input.autoUpdate) {\r\n // Update any ProductVariants' names which include the option name\r\n let oldOptionName: string | undefined;\r\n const newOptionName = findTranslation(input, languageCode)?.name;\r\n if (!newOptionName) {\r\n updateProductVariantNames$ = of([]);\r\n }\r\n const variantsToUpdate: UpdateProductVariantInput[] = [];\r\n for (const variant of variants) {\r\n if (variant.options.map(o => o.id).includes(input.id)) {\r\n if (!oldOptionName) {\r\n oldOptionName = findTranslation(\r\n variant.options.find(o => o.id === input.id),\r\n languageCode,\r\n )?.name;\r\n }\r\n const variantName = findTranslation(variant, languageCode)?.name || '';\r\n if (oldOptionName && newOptionName && variantName.includes(oldOptionName)) {\r\n variantsToUpdate.push({\r\n id: variant.id,\r\n translations: [\r\n {\r\n languageCode,\r\n name: replaceLast(variantName, oldOptionName, newOptionName),\r\n },\r\n ],\r\n });\r\n }\r\n }\r\n }\r\n if (variantsToUpdate.length) {\r\n updateProductVariantNames$ =\r\n this.dataService.product.updateProductVariants(variantsToUpdate);\r\n }\r\n }\r\n return this.dataService.product\r\n .updateProductOption(input)\r\n .pipe(mergeMap(() => updateProductVariantNames$));\r\n }),\r\n );\r\n }\r\n\r\n deleteProductVariant(id: string, productId: string) {\r\n return this.dataService.product.deleteProductVariant(id).pipe(\r\n switchMap(result => {\r\n if (result.deleteProductVariant.result === DeletionResult.DELETED) {\r\n return this.dataService.product.getProduct(productId).single$;\r\n } else {\r\n return throwError(result.deleteProductVariant.message);\r\n }\r\n }),\r\n );\r\n }\r\n}\r\n","import { switchMap } from './switchMap';\nimport { isFunction } from '../util/isFunction';\nexport function switchMapTo(innerObservable, resultSelector) {\n return isFunction(resultSelector) ? switchMap(() => innerObservable, resultSelector) : switchMap(() => innerObservable);\n}\n","<div class=\"input-wrapper\" [class.focus]=\"isFocussed\" (click)=\"textArea.focus()\">\r\n <div class=\"chips\" *ngIf=\"0 < optionValues.length\">\r\n <vdr-chip\r\n *ngFor=\"let option of optionValues; last as isLast; index as i\"\r\n [icon]=\"option.locked ? 'lock' : 'times'\"\r\n [class.selected]=\"isLast && lastSelected\"\r\n [class.locked]=\"option.locked\"\r\n [colorFrom]=\"groupName\"\r\n (iconClick)=\"removeOption(option)\"\r\n >\r\n <span [hidden]=\"editingIndex !== i\">\r\n <input\r\n #editNameInput\r\n type=\"text\"\r\n [ngModel]=\"option.name\"\r\n (blur)=\"updateOption(i, $event)\"\r\n (click)=\"$event.cancelBubble = true\"\r\n />\r\n </span>\r\n <span\r\n class=\"option-name\"\r\n [class.editable]=\"!option.locked && !option.id\"\r\n (click)=\"editName(i, $event)\" [hidden]=\"editingIndex === i\">{{ option.name }}</span>\r\n </vdr-chip>\r\n </div>\r\n <textarea\r\n #textArea\r\n (keyup)=\"handleKey($event)\"\r\n (focus)=\"isFocussed = true\"\r\n (blur)=\"handleBlur()\"\r\n [(ngModel)]=\"input\"\r\n [disabled]=\"disabled\"\r\n ></textarea>\r\n</div>\r\n","import {\r\n ChangeDetectionStrategy,\r\n ChangeDetectorRef,\r\n Component,\r\n ElementRef,\r\n EventEmitter,\r\n forwardRef,\r\n Input,\r\n OnChanges,\r\n OnInit,\r\n Output,\r\n Provider,\r\n QueryList,\r\n SimpleChanges,\r\n ViewChild,\r\n ViewChildren,\r\n} from '@angular/core';\r\nimport { ControlValueAccessor, NG_VALUE_ACCESSOR } from '@angular/forms';\r\nimport { unique } from '@vendure/common/lib/unique';\r\n\r\nexport const OPTION_VALUE_INPUT_VALUE_ACCESSOR: Provider = {\r\n provide: NG_VALUE_ACCESSOR,\r\n useExisting: forwardRef(() => OptionValueInputComponent),\r\n multi: true,\r\n};\r\n\r\ninterface Option {\r\n id?: string;\r\n name: string;\r\n locked: boolean;\r\n}\r\n\r\n@Component({\r\n selector: 'vdr-option-value-input',\r\n templateUrl: './option-value-input.component.html',\r\n styleUrls: ['./option-value-input.component.scss'],\r\n changeDetection: ChangeDetectionStrategy.Default,\r\n providers: [OPTION_VALUE_INPUT_VALUE_ACCESSOR],\r\n})\r\nexport class OptionValueInputComponent implements ControlValueAccessor {\r\n @Input() groupName = '';\r\n @ViewChild('textArea', { static: true }) textArea: ElementRef<HTMLTextAreaElement>;\r\n @ViewChildren('editNameInput', { read: ElementRef }) nameInputs: QueryList<ElementRef>;\r\n @Input() options: Option[];\r\n @Output() add = new EventEmitter<Option>();\r\n @Output() remove = new EventEmitter<Option>();\r\n @Output() edit = new EventEmitter<{ index: number; option: Option }>();\r\n @Input() disabled = false;\r\n input = '';\r\n isFocussed = false;\r\n lastSelected = false;\r\n formValue: Option[];\r\n editingIndex = -1;\r\n onChangeFn: (value: any) => void;\r\n onTouchFn: (value: any) => void;\r\n\r\n get optionValues(): Option[] {\r\n return this.formValue ?? this.options ?? [];\r\n }\r\n\r\n constructor(private changeDetector: ChangeDetectorRef) {}\r\n\r\n registerOnChange(fn: any): void {\r\n this.onChangeFn = fn;\r\n }\r\n\r\n registerOnTouched(fn: any): void {\r\n this.onTouchFn = fn;\r\n }\r\n\r\n setDisabledState(isDisabled: boolean): void {\r\n this.disabled = isDisabled;\r\n this.changeDetector.markForCheck();\r\n }\r\n\r\n writeValue(obj: any): void {\r\n this.formValue = obj || [];\r\n }\r\n\r\n focus() {\r\n this.textArea.nativeElement.focus();\r\n }\r\n\r\n editName(index: number, event: MouseEvent) {\r\n const optionValue = this.optionValues[index];\r\n if (!optionValue.locked && !optionValue.id) {\r\n event.cancelBubble = true;\r\n this.editingIndex = index;\r\n const input = this.nameInputs.get(index)?.nativeElement;\r\n setTimeout(() => input?.focus());\r\n }\r\n }\r\n\r\n updateOption(index: number, event: InputEvent) {\r\n const optionValue = this.optionValues[index];\r\n const newName = (event.target as HTMLInputElement).value;\r\n if (optionValue) {\r\n if (newName) {\r\n optionValue.name = newName;\r\n this.edit.emit({ index, option: optionValue });\r\n }\r\n this.editingIndex = -1;\r\n }\r\n }\r\n\r\n removeOption(option: Option) {\r\n if (!option.locked) {\r\n if (this.formValue) {\r\n this.formValue = this.formValue?.filter(o => o.name !== option.name);\r\n this.onChangeFn(this.formValue);\r\n } else {\r\n this.remove.emit(option);\r\n }\r\n }\r\n }\r\n\r\n handleKey(event: KeyboardEvent) {\r\n switch (event.key) {\r\n case ',':\r\n case 'Enter':\r\n this.addOptionValue();\r\n event.preventDefault();\r\n break;\r\n case 'Backspace':\r\n if (this.lastSelected) {\r\n this.removeLastOption();\r\n this.lastSelected = false;\r\n } else if (this.input === '') {\r\n this.lastSelected = true;\r\n }\r\n break;\r\n default:\r\n this.lastSelected = false;\r\n }\r\n }\r\n\r\n handleBlur() {\r\n this.isFocussed = false;\r\n this.addOptionValue();\r\n }\r\n\r\n private addOptionValue() {\r\n const options = this.parseInputIntoOptions(this.input).filter(option => {\r\n // do not add an option with the same name\r\n // as an existing option\r\n const existing = this.options ?? this.formValue;\r\n return !existing?.find(o => o?.name === option.name);\r\n });\r\n if (!this.formValue && this.options) {\r\n for (const option of options) {\r\n this.add.emit(option);\r\n }\r\n } else {\r\n this.formValue = unique([...this.formValue, ...options]);\r\n this.onChangeFn(this.formValue);\r\n }\r\n this.input = '';\r\n }\r\n\r\n private parseInputIntoOptions(input: string): Option[] {\r\n return input\r\n .split(/[,\\n]/)\r\n .map(s => s.trim())\r\n .filter(s => s !== '')\r\n .map(s => ({ name: s, locked: false }));\r\n }\r\n\r\n private removeLastOption() {\r\n if (this.optionValues.length) {\r\n const option = this.optionValues[this.optionValues.length - 1];\r\n this.removeOption(option);\r\n }\r\n }\r\n}\r\n","<div *ngFor=\"let group of optionGroups\" class=\"option-groups\">\r\n <div class=\"name\">\r\n <label>{{ 'catalog.option' | translate }}</label>\r\n <input\r\n #optionGroupName\r\n placeholder=\"e.g. Size\"\r\n clrInput\r\n [(ngModel)]=\"group.name\"\r\n name=\"name\"\r\n required\r\n (keydown.enter)=\"handleEnter($event, optionValueInputComponent)\"\r\n />\r\n </div>\r\n <div class=\"values\">\r\n <label>{{ 'catalog.option-values' | translate }}</label>\r\n <vdr-option-value-input\r\n #optionValueInputComponent\r\n [(ngModel)]=\"group.values\"\r\n (ngModelChange)=\"generateVariants()\"\r\n (edit)=\"generateVariants()\"\r\n [groupName]=\"group.name\"\r\n [disabled]=\"group.name === ''\"\r\n ></vdr-option-value-input>\r\n </div>\r\n <div class=\"remove-group\">\r\n <button\r\n class=\"btn btn-icon btn-warning-outline\"\r\n [title]=\"'catalog.remove-option' | translate\"\r\n (click)=\"removeOption(group.name)\"\r\n >\r\n <clr-icon shape=\"trash\"></clr-icon>\r\n </button>\r\n </div>\r\n</div>\r\n<button class=\"btn btn-primary-outline btn-sm\" (click)=\"addOption()\">\r\n <clr-icon shape=\"plus\"></clr-icon>\r\n {{ 'catalog.add-option' | translate }}\r\n</button>\r\n\r\n<div class=\"variants-preview\">\r\n <table class=\"table\">\r\n <thead>\r\n <tr>\r\n <th *ngIf=\"1 < variants.length\">{{ 'common.create' | translate }}</th>\r\n <th *ngIf=\"1 < variants.length\">{{ 'catalog.variant' | translate }}</th>\r\n <th>{{ 'catalog.sku' | translate }}</th>\r\n <th>{{ 'catalog.price' | translate }}</th>\r\n <th>{{ 'catalog.stock-on-hand' | translate }}</th>\r\n </tr>\r\n </thead>\r\n <tr\r\n *ngFor=\"let variant of variants; trackBy: trackByFn\"\r\n [class.disabled]=\"!variantFormValues[variant.id].enabled\"\r\n >\r\n <td *ngIf=\"1 < variants.length\">\r\n <input\r\n type=\"checkbox\"\r\n (change)=\"onFormChange()\"\r\n [(ngModel)]=\"variantFormValues[variant.id].enabled\"\r\n clrCheckbox\r\n />\r\n </td>\r\n <td *ngIf=\"1 < variants.length\">\r\n {{ variant.values.join(' ') }}\r\n </td>\r\n <td>\r\n <clr-input-container>\r\n <input\r\n clrInput\r\n type=\"text\"\r\n (change)=\"onFormChange()\"\r\n [(ngModel)]=\"variantFormValues[variant.id].sku\"\r\n [placeholder]=\"'catalog.sku' | translate\"\r\n />\r\n </clr-input-container>\r\n </td>\r\n <td>\r\n <clr-input-container>\r\n <vdr-currency-input\r\n clrInput\r\n [(ngModel)]=\"variantFormValues[variant.id].price\"\r\n (ngModelChange)=\"onFormChange()\"\r\n [currencyCode]=\"currencyCode\"\r\n ></vdr-currency-input>\r\n </clr-input-container>\r\n </td>\r\n <td>\r\n <clr-input-container>\r\n <input\r\n clrInput\r\n type=\"number\"\r\n [(ngModel)]=\"variantFormValues[variant.id].stock\"\r\n (change)=\"onFormChange()\"\r\n min=\"0\"\r\n step=\"1\"\r\n />\r\n </clr-input-container>\r\n </td>\r\n </tr>\r\n </table>\r\n</div>\r\n","import { Component, ElementRef, EventEmitter, OnInit, Output, QueryList, ViewChildren } from '@angular/core';\r\nimport { CurrencyCode, DataService } from '@vendure/admin-ui/core';\r\nimport { generateAllCombinations } from '@vendure/common/lib/shared-utils';\r\n\r\nimport { OptionValueInputComponent } from '../option-value-input/option-value-input.component';\r\n\r\nconst DEFAULT_VARIANT_CODE = '__DEFAULT_VARIANT__';\r\nexport type CreateVariantValues = {\r\n optionValues: string[];\r\n enabled: boolean;\r\n sku: string;\r\n price: number;\r\n stock: number;\r\n};\r\nexport type CreateProductVariantsConfig = {\r\n groups: Array<{ name: string; values: string[] }>;\r\n variants: CreateVariantValues[];\r\n};\r\n\r\n@Component({\r\n selector: 'vdr-generate-product-variants',\r\n templateUrl: './generate-product-variants.component.html',\r\n styleUrls: ['./generate-product-variants.component.scss'],\r\n})\r\nexport class GenerateProductVariantsComponent implements OnInit {\r\n @Output() variantsChange = new EventEmitter<CreateProductVariantsConfig>();\r\n @ViewChildren('optionGroupName', { read: ElementRef }) groupNameInputs: QueryList<ElementRef>;\r\n optionGroups: Array<{ name: string; values: Array<{ name: string; locked: boolean }> }> = [];\r\n currencyCode: CurrencyCode;\r\n variants: Array<{ id: string; values: string[] }>;\r\n variantFormValues: { [id: string]: CreateVariantValues } = {};\r\n constructor(private dataService: DataService) {}\r\n\r\n ngOnInit() {\r\n this.dataService.settings.getActiveChannel().single$.subscribe(data => {\r\n this.currencyCode = data.activeChannel.currencyCode;\r\n });\r\n\r\n this.generateVariants();\r\n }\r\n\r\n addOption() {\r\n this.optionGroups.push({ name: '', values: [] });\r\n const index = this.optionGroups.length - 1;\r\n setTimeout(() => {\r\n const input = this.groupNameInputs.get(index)?.nativeElement;\r\n input?.focus();\r\n });\r\n }\r\n\r\n removeOption(name: string) {\r\n this.optionGroups = this.optionGroups.filter(g => g.name !== name);\r\n this.generateVariants();\r\n }\r\n\r\n generateVariants() {\r\n const totalValuesCount = this.optionGroups.reduce((sum, group) => sum + group.values.length, 0);\r\n const groups = totalValuesCount\r\n ? this.optionGroups.map(g => g.values.map(v => v.name))\r\n : [[DEFAULT_VARIANT_CODE]];\r\n this.variants = generateAllCombinations(groups).map(values => ({ id: values.join('|'), values }));\r\n\r\n this.variants.forEach(variant => {\r\n if (!this.variantFormValues[variant.id]) {\r\n this.variantFormValues[variant.id] = {\r\n optionValues: variant.values,\r\n enabled: true,\r\n price: this.copyFromDefault(variant.id, 'price', 0),\r\n sku: this.copyFromDefault(variant.id, 'sku', ''),\r\n stock: this.copyFromDefault(variant.id, 'stock', 0),\r\n };\r\n }\r\n });\r\n this.onFormChange();\r\n }\r\n\r\n trackByFn(index: number, variant: { name: string; values: string[] }) {\r\n return variant.values.join('|');\r\n }\r\n\r\n handleEnter(event: KeyboardEvent, optionValueInputComponent: OptionValueInputComponent) {\r\n event.preventDefault();\r\n event.stopPropagation();\r\n optionValueInputComponent.focus();\r\n }\r\n\r\n onFormChange() {\r\n const variantsToCreate = this.variants.map(v => this.variantFormValues[v.id]).filter(v => v.enabled);\r\n this.variantsChange.emit({\r\n groups: this.optionGroups.map(og => ({ name: og.name, values: og.values.map(v => v.name) })),\r\n variants: variantsToCreate,\r\n });\r\n }\r\n\r\n private copyFromDefault<T extends keyof CreateVariantValues>(\r\n variantId: string,\r\n prop: T,\r\n value: CreateVariantValues[T],\r\n ): CreateVariantValues[T] {\r\n return variantId !== DEFAULT_VARIANT_CODE\r\n ? this.variantFormValues[DEFAULT_VARIANT_CODE][prop]\r\n : value;\r\n }\r\n}\r\n","<table class=\"table\">\r\n <thead>\r\n <tr>\r\n <th></th>\r\n <th>{{ 'common.name' | translate }}</th>\r\n <th>{{ 'catalog.sku' | translate }}</th>\r\n <ng-container *ngFor=\"let optionGroup of optionGroups | sort: 'id'\">\r\n <th>{{ optionGroup.name }}</th>\r\n </ng-container>\r\n <th>{{ 'catalog.price' | translate }}</th>\r\n <th>{{ 'catalog.stock-on-hand' | translate }}</th>\r\n <th>{{ 'common.enabled' | translate }}</th>\r\n </tr>\r\n </thead>\r\n <tbody>\r\n <tr *ngFor=\"let variant of variants | paginate: paginationConfig; index as i; trackBy: trackByFn\">\r\n <ng-container *ngIf=\"formGroupMap.get(variant.id) as formGroup\" [formGroup]=\"formGroup\">\r\n <td class=\"left align-middle\" [class.disabled]=\"!formGroup.get('enabled')!.value\">\r\n <div class=\"card-img\">\r\n <div class=\"featured-asset\">\r\n <img\r\n *ngIf=\"getFeaturedAsset(variant) as featuredAsset; else placeholder\"\r\n [src]=\"featuredAsset | assetPreview: 'tiny'\"\r\n />\r\n <ng-template #placeholder>\r\n <div class=\"placeholder\">\r\n <clr-icon shape=\"image\" size=\"48\"></clr-icon>\r\n </div>\r\n </ng-template>\r\n </div>\r\n </div>\r\n </td>\r\n <td class=\"left align-middle\" [class.disabled]=\"!formGroup.get('enabled')!.value\">\r\n <clr-input-container>\r\n <input\r\n clrInput\r\n type=\"text\"\r\n formControlName=\"name\"\r\n [readonly]=\"!(updatePermission | hasPermission)\"\r\n [placeholder]=\"'common.name' | translate\"\r\n />\r\n </clr-input-container>\r\n </td>\r\n <td class=\"left align-middle\" [class.disabled]=\"!formGroup.get('enabled')!.value\">\r\n <clr-input-container>\r\n <input\r\n clrInput\r\n type=\"text\"\r\n formControlName=\"sku\"\r\n [readonly]=\"!(updatePermission | hasPermission)\"\r\n [placeholder]=\"'catalog.sku' | translate\"\r\n />\r\n </clr-input-container>\r\n </td>\r\n <ng-container *ngFor=\"let option of variant.options | sort: 'groupId'\">\r\n <td\r\n class=\"left align-middle\"\r\n [class.disabled]=\"!formGroup.get('enabled')!.value\"\r\n [style.color]=\"optionGroupName(option.groupId) | stringToColor\"\r\n >\r\n {{ option.name }}\r\n </td>\r\n </ng-container>\r\n <td class=\"left align-middle price\" [class.disabled]=\"!formGroup.get('enabled')!.value\">\r\n <clr-input-container>\r\n <vdr-currency-input\r\n *ngIf=\"!channelPriceIncludesTax\"\r\n clrInput\r\n [currencyCode]=\"variant.currencyCode\"\r\n [readonly]=\"!(updatePermission | hasPermission)\"\r\n formControlName=\"price\"\r\n ></vdr-currency-input>\r\n <vdr-currency-input\r\n *ngIf=\"channelPriceIncludesTax\"\r\n clrInput\r\n [currencyCode]=\"variant.currencyCode\"\r\n [readonly]=\"!(updatePermission | hasPermission)\"\r\n formControlName=\"priceWithTax\"\r\n ></vdr-currency-input>\r\n </clr-input-container>\r\n </td>\r\n <td class=\"left align-middle stock\" [class.disabled]=\"!formGroup.get('enabled')!.value\">\r\n <clr-input-container>\r\n <input\r\n clrInput\r\n type=\"number\"\r\n min=\"0\"\r\n step=\"1\"\r\n formControlName=\"stockOnHand\"\r\n [readonly]=\"!(updatePermission | hasPermission)\"\r\n />\r\n </clr-input-container>\r\n </td>\r\n <td class=\"left align-middle stock\" [class.disabled]=\"!formGroup.get('enabled')!.value\">\r\n <clr-toggle-wrapper>\r\n <input\r\n type=\"checkbox\"\r\n clrToggle\r\n name=\"enabled\"\r\n formControlName=\"enabled\"\r\n [vdrDisabled]=\"!(updatePermission | hasPermission)\"\r\n />\r\n </clr-toggle-wrapper>\r\n </td>\r\n </ng-container>\r\n </tr>\r\n </tbody>\r\n</table>\r\n","import {\r\n ChangeDetectionStrategy,\r\n ChangeDetectorRef,\r\n Component,\r\n Input,\r\n OnDestroy,\r\n OnInit,\r\n} from '@angular/core';\r\nimport { FormArray, FormGroup } from '@angular/forms';\r\nimport { Permission, ProductDetailFragment, ProductVariantFragment } from '@vendure/admin-ui/core';\r\nimport { Subscription } from 'rxjs';\r\nimport { debounceTime, distinctUntilChanged, map } from 'rxjs/operators';\r\n\r\nimport { PaginationConfig, SelectedAssets } from '../product-detail/product-detail.types';\r\n\r\n@Component({\r\n selector: 'vdr-product-variants-table',\r\n templateUrl: './product-variants-table.component.html',\r\n styleUrls: ['./product-variants-table.component.scss'],\r\n changeDetection: ChangeDetectionStrategy.OnPush,\r\n})\r\nexport class ProductVariantsTableComponent implements OnInit, OnDestroy {\r\n @Input('productVariantsFormArray') formArray: FormArray;\r\n @Input() variants: ProductVariantFragment[];\r\n @Input() paginationConfig: PaginationConfig;\r\n @Input() channelPriceIncludesTax: boolean;\r\n @Input() optionGroups: ProductDetailFragment['optionGroups'];\r\n @Input() pendingAssetChanges: { [variantId: string]: SelectedAssets };\r\n formGroupMap = new Map<string, FormGroup>();\r\n readonly updatePermission = [Permission.UpdateCatalog, Permission.UpdateProduct];\r\n private subscription: Subscription;\r\n\r\n constructor(private changeDetector: ChangeDetectorRef) {}\r\n\r\n ngOnInit() {\r\n this.subscription = this.formArray.valueChanges\r\n .pipe(\r\n map(value => value.length),\r\n debounceTime(1),\r\n distinctUntilChanged(),\r\n )\r\n .subscribe(() => {\r\n this.buildFormGroupMap();\r\n });\r\n\r\n this.buildFormGroupMap();\r\n }\r\n\r\n ngOnDestroy() {\r\n if (this.subscription) {\r\n this.subscription.unsubscribe();\r\n }\r\n }\r\n\r\n trackByFn(index: number, item: any) {\r\n if ((item as any).id != null) {\r\n return (item as any).id;\r\n } else {\r\n return index;\r\n }\r\n }\r\n\r\n getFeaturedAsset(variant: ProductVariantFragment) {\r\n return this.pendingAssetChanges[variant.id]?.featuredAsset || variant.featuredAsset;\r\n }\r\n\r\n optionGroupName(optionGroupId: string): string | undefined {\r\n const group = this.optionGroups.find(g => g.id === optionGroupId);\r\n return group && group.name;\r\n }\r\n\r\n private buildFormGroupMap() {\r\n this.formGroupMap.clear();\r\n for (const controlGroup of this.formArray.controls) {\r\n this.formGroupMap.set(controlGroup.value.id, controlGroup as FormGroup);\r\n }\r\n this.changeDetector.markForCheck();\r\n }\r\n}\r\n","<ng-template vdrDialogTitle>{{ 'catalog.update-product-option' | translate }}</ng-template>\r\n<vdr-form-field [label]=\"'catalog.option-name' | translate\" for=\"name\">\r\n <input\r\n id=\"name\"\r\n type=\"text\"\r\n #nameInput=\"ngModel\"\r\n [(ngModel)]=\"name\"\r\n required\r\n (input)=\"updateCode($event.target.value)\"\r\n />\r\n</vdr-form-field>\r\n<vdr-form-field [label]=\"'common.code' | translate\" for=\"code\">\r\n <input id=\"code\" type=\"text\" #codeInput=\"ngModel\" required [(ngModel)]=\"code\" pattern=\"[a-z0-9_-]+\" />\r\n</vdr-form-field>\r\n<clr-checkbox-wrapper>\r\n <input type=\"checkbox\" clrCheckbox [(ngModel)]=\"updateVariantName\" />\r\n <label>{{ 'catalog.auto-update-option-variant-name' | translate }}</label>\r\n</clr-checkbox-wrapper>\r\n<section *ngIf=\"customFields.length\">\r\n <label>{{ 'common.custom-fields' | translate }}</label>\r\n <vdr-tabbed-custom-fields\r\n entityName=\"ProductOption\"\r\n [customFields]=\"customFields\"\r\n [customFieldsFormGroup]=\"customFieldsForm\"\r\n [readonly]=\"!(['UpdateCatalog', 'UpdateProduct'] | hasPermission)\"\r\n ></vdr-tabbed-custom-fields>\r\n</section>\r\n\r\n<ng-template vdrDialogButtons>\r\n <button type=\"button\" class=\"btn\" (click)=\"cancel()\">{{ 'common.cancel' | translate }}</button>\r\n <button\r\n type=\"submit\"\r\n (click)=\"update()\"\r\n [disabled]=\"\r\n nameInput.invalid ||\r\n codeInput.invalid ||\r\n (nameInput.pristine && codeInput.pristine && customFieldsForm.pristine)\r\n \"\r\n class=\"btn btn-primary\"\r\n >\r\n {{ 'catalog.update-product-option' | translate }}\r\n </button>\r\n</ng-template>\r\n","import { ChangeDetectionStrategy, Component, OnInit } from '@angular/core';\r\nimport { FormControl, FormGroup } from '@angular/forms';\r\nimport {\r\n CustomFieldConfig,\r\n LanguageCode,\r\n ProductVariantFragment,\r\n UpdateProductOptionInput,\r\n} from '@vendure/admin-ui/core';\r\nimport { createUpdatedTranslatable } from '@vendure/admin-ui/core';\r\nimport { Dialog } from '@vendure/admin-ui/core';\r\nimport { normalizeString } from '@vendure/common/lib/normalize-string';\r\n\r\n@Component({\r\n selector: 'vdr-update-product-option-dialog',\r\n templateUrl: './update-product-option-dialog.component.html',\r\n styleUrls: ['./update-product-option-dialog.component.scss'],\r\n changeDetection: ChangeDetectionStrategy.OnPush,\r\n})\r\nexport class UpdateProductOptionDialogComponent\r\n implements Dialog<UpdateProductOptionInput & { autoUpdate: boolean }>, OnInit\r\n{\r\n resolveWith: (result?: UpdateProductOptionInput & { autoUpdate: boolean }) => void;\r\n updateVariantName = true;\r\n // Provided by caller\r\n productOption: ProductVariantFragment['options'][number];\r\n activeLanguage: LanguageCode;\r\n name: string;\r\n code: string;\r\n customFields: CustomFieldConfig[];\r\n codeInputTouched = false;\r\n customFieldsForm: FormGroup;\r\n\r\n ngOnInit(): void {\r\n const currentTranslation = this.productOption.translations.find(\r\n t => t.languageCode === this.activeLanguage,\r\n );\r\n this.name = currentTranslation?.name ?? '';\r\n this.code = this.productOption.code;\r\n this.customFieldsForm = new FormGroup({});\r\n if (this.customFields) {\r\n const cfCurrentTranslation =\r\n (currentTranslation && (currentTranslation as any).customFields) || {};\r\n\r\n for (const fieldDef of this.customFields) {\r\n const key = fieldDef.name;\r\n const value =\r\n fieldDef.type === 'localeString'\r\n ? cfCurrentTranslation[key]\r\n : (this.productOption as any).customFields[key];\r\n this.customFieldsForm.addControl(fieldDef.name, new FormControl(value));\r\n }\r\n }\r\n }\r\n\r\n update() {\r\n const result = createUpdatedTranslatable({\r\n translatable: this.productOption,\r\n languageCode: this.activeLanguage,\r\n updatedFields: {\r\n code: this.code,\r\n name: this.name,\r\n customFields: this.customFieldsForm.value,\r\n },\r\n customFieldConfig: this.customFields,\r\n defaultTranslation: {\r\n languageCode: this.activeLanguage,\r\n name: '',\r\n },\r\n });\r\n this.resolveWith({ ...result, autoUpdate: this.updateVariantName });\r\n }\r\n\r\n cancel() {\r\n this.resolveWith();\r\n }\r\n\r\n updateCode(nameValue: string) {\r\n if (!this.codeInputTouched && !this.productOption.code) {\r\n this.code = normalizeString(nameValue, '-');\r\n }\r\n }\r\n}\r\n","<label class=\"clr-control-label\">{{ 'catalog.taxes' | translate }}</label>\r\n<div *ngIf=\"priceIncludesTax\" class=\"value\">\r\n {{ 'catalog.price-includes-tax-at' | translate: { rate: taxRate$ | async } }}\r\n</div>\r\n<div *ngIf=\"!priceIncludesTax\" class=\"value\">\r\n {{\r\n 'catalog.price-with-tax-in-default-zone'\r\n | translate: { price: grossPrice$ | async | localeCurrency: currencyCode, rate: taxRate$ | async }\r\n }}\r\n</div>\r\n","import { ChangeDetectionStrategy, Component, Input, OnChanges, OnInit, SimpleChanges } from '@angular/core';\r\nimport { DataService } from '@vendure/admin-ui/core';\r\nimport { BehaviorSubject, combineLatest, Observable, Subject } from 'rxjs';\r\nimport { map } from 'rxjs/operators';\r\n\r\n@Component({\r\n selector: 'vdr-variant-price-detail',\r\n templateUrl: './variant-price-detail.component.html',\r\n styleUrls: ['./variant-price-detail.component.scss'],\r\n changeDetection: ChangeDetectionStrategy.OnPush,\r\n})\r\nexport class VariantPriceDetailComponent implements OnInit, OnChanges {\r\n @Input() priceIncludesTax: boolean;\r\n @Input() price: number;\r\n @Input() currencyCode: string;\r\n @Input() taxCategoryId: string;\r\n\r\n grossPrice$: Observable<number>;\r\n taxRate$: Observable<number>;\r\n\r\n private priceChange$ = new BehaviorSubject<number>(0);\r\n private taxCategoryIdChange$ = new BehaviorSubject<string>('');\r\n\r\n constructor(private dataService: DataService) {}\r\n\r\n ngOnInit() {\r\n const taxRates$ = this.dataService.settings\r\n .getTaxRatesSimple(999, 0, 'cache-first')\r\n .mapStream(data => data.taxRates.items);\r\n const activeChannel$ = this.dataService.settings\r\n .getActiveChannel('cache-first')\r\n .refetchOnChannelChange()\r\n .mapStream(data => data.activeChannel);\r\n\r\n this.taxRate$ = combineLatest(activeChannel$, taxRates$, this.taxCategoryIdChange$).pipe(\r\n map(([channel, taxRates, taxCategoryId]) => {\r\n const defaultTaxZone = channel.defaultTaxZone;\r\n if (!defaultTaxZone) {\r\n return 0;\r\n }\r\n const applicableRate = taxRates.find(\r\n taxRate => taxRate.zone.id === defaultTaxZone.id && taxRate.category.id === taxCategoryId,\r\n );\r\n\r\n if (!applicableRate) {\r\n return 0;\r\n }\r\n return applicableRate.value;\r\n }),\r\n );\r\n\r\n this.grossPrice$ = combineLatest(this.taxRate$, this.priceChange$).pipe(\r\n map(([taxRate, price]) => {\r\n return Math.round(price * ((100 + taxRate) / 100));\r\n }),\r\n );\r\n }\r\n\r\n ngOnChanges(changes: SimpleChanges): void {\r\n if ('price' in changes) {\r\n this.priceChange$.next(changes.price.currentValue);\r\n }\r\n if ('taxCategoryId' in changes) {\r\n this.taxCategoryIdChange$.next(changes.taxCategoryId.currentValue);\r\n }\r\n }\r\n}\r\n","<div class=\"variants-list\">\r\n <div\r\n class=\"variant-container card\"\r\n *ngFor=\"\r\n let variant of variants | paginate: paginationConfig || { itemsPerPage: 10, currentPage: 1 };\r\n trackBy: trackById;\r\n let i = index\r\n \"\r\n [class.disabled]=\"!formGroupMap.get(variant.id)?.get('enabled')?.value\"\r\n >\r\n <ng-container *ngIf=\"formGroupMap.get(variant.id) as formGroup\" [formGroup]=\"formGroup\">\r\n <div class=\"card-block header-row\">\r\n <div class=\"details\">\r\n <vdr-title-input class=\"sku\" [readonly]=\"!(updatePermission | hasPermission)\">\r\n <clr-input-container>\r\n <input\r\n clrInput\r\n type=\"text\"\r\n formControlName=\"sku\"\r\n [readonly]=\"!(updatePermission | hasPermission)\"\r\n [placeholder]=\"'catalog.sku' | translate\"\r\n />\r\n </clr-input-container>\r\n </vdr-title-input>\r\n <vdr-title-input class=\"name\" [readonly]=\"!(updatePermission | hasPermission)\">\r\n <clr-input-container>\r\n <input\r\n clrInput\r\n type=\"text\"\r\n formControlName=\"name\"\r\n [readonly]=\"!(updatePermission | hasPermission)\"\r\n [placeholder]=\"'common.name' | translate\"\r\n />\r\n </clr-input-container>\r\n </vdr-title-input>\r\n </div>\r\n <div class=\"right-controls\">\r\n <clr-toggle-wrapper *vdrIfPermissions=\"updatePermission\">\r\n <input type=\"checkbox\" clrToggle name=\"enabled\" formControlName=\"enabled\" />\r\n <label>{{ 'common.enabled' | translate }}</label>\r\n </clr-toggle-wrapper>\r\n </div>\r\n </div>\r\n <div class=\"card-block\">\r\n <div class=\"variant-body\">\r\n <div class=\"assets\">\r\n <vdr-assets\r\n [compact]=\"true\"\r\n [assets]=\"pendingAssetChanges[variant.id]?.assets || variant.assets\"\r\n [featuredAsset]=\"\r\n pendingAssetChanges[variant.id]?.featuredAsset || variant.featuredAsset\r\n \"\r\n [updatePermissions]=\"updatePermission\"\r\n (change)=\"onAssetChange(variant.id, $event)\"\r\n ></vdr-assets>\r\n </div>\r\n <div class=\"variant-form-inputs\">\r\n <div class=\"standard-fields\">\r\n <div class=\"variant-form-input-row\">\r\n <div class=\"tax-category\">\r\n <clr-select-container\r\n *vdrIfPermissions=\"updatePermission; else taxCategoryLabel\"\r\n >\r\n <label>{{ 'catalog.tax-category' | translate }}</label>\r\n <select clrSelect name=\"options\" formControlName=\"taxCategoryId\">\r\n <option\r\n *ngFor=\"let taxCategory of taxCategories\"\r\n [value]=\"taxCategory.id\"\r\n >\r\n {{ taxCategory.name }}\r\n </option>\r\n </select>\r\n </clr-select-container>\r\n <ng-template #taxCategoryLabel>\r\n <label class=\"clr-control-label\">{{\r\n 'catalog.tax-category' | translate\r\n }}</label>\r\n <div class=\"tax-category-label\">\r\n {{ getTaxCategoryName(formGroup) }}\r\n </div>\r\n </ng-template>\r\n </div>\r\n <div class=\"price\">\r\n <clr-input-container>\r\n <label>{{ 'catalog.price' | translate }}</label>\r\n <vdr-currency-input\r\n *ngIf=\"!channelPriceIncludesTax\"\r\n clrInput\r\n [currencyCode]=\"variant.currencyCode\"\r\n [readonly]=\"!(updatePermission | hasPermission)\"\r\n formControlName=\"price\"\r\n ></vdr-currency-input>\r\n <vdr-currency-input\r\n *ngIf=\"channelPriceIncludesTax\"\r\n clrInput\r\n [currencyCode]=\"variant.currencyCode\"\r\n [readonly]=\"!(updatePermission | hasPermission)\"\r\n formControlName=\"priceWithTax\"\r\n ></vdr-currency-input>\r\n </clr-input-container>\r\n </div>\r\n <vdr-variant-price-detail\r\n [price]=\"formGroup.get('price')!.value\"\r\n [currencyCode]=\"variant.currencyCode\"\r\n [priceIncludesTax]=\"channelPriceIncludesTax\"\r\n [taxCategoryId]=\"formGroup.get('taxCategoryId')!.value\"\r\n ></vdr-variant-price-detail>\r\n </div>\r\n <div class=\"variant-form-input-row\">\r\n <clr-select-container *vdrIfPermissions=\"updatePermission\">\r\n <label\r\n >{{ 'catalog.track-inventory' | translate }}\r\n <vdr-help-tooltip\r\n [content]=\"'catalog.track-inventory-tooltip' | translate\"\r\n ></vdr-help-tooltip>\r\n </label>\r\n <select clrSelect name=\"options\" formControlName=\"trackInventory\">\r\n <option [value]=\"GlobalFlag.TRUE\">\r\n {{ 'catalog.track-inventory-true' | translate }}\r\n </option>\r\n <option [value]=\"GlobalFlag.FALSE\">\r\n {{ 'catalog.track-inventory-false' | translate }}\r\n </option>\r\n <option [value]=\"GlobalFlag.INHERIT\">\r\n {{ 'catalog.track-inventory-inherit' | translate }}\r\n </option>\r\n </select>\r\n </clr-select-container>\r\n <clr-input-container>\r\n <label\r\n >{{ 'catalog.stock-on-hand' | translate }}\r\n <vdr-help-tooltip\r\n [content]=\"'catalog.stock-on-hand-tooltip' | translate\"\r\n ></vdr-help-tooltip\r\n ></label>\r\n <input\r\n [class.inventory-untracked]=\"inventoryIsNotTracked(formGroup)\"\r\n clrInput\r\n type=\"number\"\r\n [min]=\"getStockOnHandMinValue(formGroup)\"\r\n step=\"1\"\r\n formControlName=\"stockOnHand\"\r\n [readonly]=\"!(updatePermission | hasPermission)\"\r\n [vdrDisabled]=\"inventoryIsNotTracked(formGroup)\"\r\n />\r\n </clr-input-container>\r\n <div [class.inventory-untracked]=\"inventoryIsNotTracked(formGroup)\">\r\n <label class=\"clr-control-label\"\r\n >{{ 'catalog.stock-allocated' | translate }}\r\n <vdr-help-tooltip\r\n [content]=\"'catalog.stock-allocated-tooltip' | translate\"\r\n ></vdr-help-tooltip\r\n ></label>\r\n <div class=\"value\">\r\n {{ variant.stockAllocated }}\r\n </div>\r\n </div>\r\n <div [class.inventory-untracked]=\"inventoryIsNotTracked(formGroup)\">\r\n <label class=\"clr-control-label\"\r\n >{{ 'catalog.stock-saleable' | translate }}\r\n <vdr-help-tooltip\r\n [content]=\"'catalog.stock-saleable-tooltip' | translate\"\r\n ></vdr-help-tooltip\r\n ></label>\r\n <div class=\"value\">\r\n {{ getSaleableStockLevel(variant) }}\r\n </div>\r\n </div>\r\n </div>\r\n\r\n <div class=\"variant-form-input-row\">\r\n <div\r\n class=\"out-of-stock-threshold-wrapper\"\r\n [class.inventory-untracked]=\"inventoryIsNotTracked(formGroup)\"\r\n >\r\n <label class=\"clr-control-label\"\r\n >{{ 'catalog.out-of-stock-threshold' | translate\r\n }}<vdr-help-tooltip\r\n [content]=\"'catalog.out-of-stock-threshold-tooltip' | translate\"\r\n ></vdr-help-tooltip\r\n ></label>\r\n <div class=\"flex\">\r\n <clr-input-container>\r\n <input\r\n clrInput\r\n type=\"number\"\r\n [formControl]=\"formGroup.get('outOfStockThreshold')\"\r\n [readonly]=\"!(updatePermission | hasPermission)\"\r\n [vdrDisabled]=\"\r\n formGroup.get('useGlobalOutOfStockThreshold')?.value !==\r\n false || inventoryIsNotTracked(formGroup)\r\n \"\r\n />\r\n </clr-input-container>\r\n <clr-toggle-wrapper>\r\n <input\r\n type=\"checkbox\"\r\n clrToggle\r\n name=\"useGlobalOutOfStockThreshold\"\r\n formControlName=\"useGlobalOutOfStockThreshold\"\r\n [vdrDisabled]=\"\r\n !(updatePermission | hasPermission) ||\r\n inventoryIsNotTracked(formGroup)\r\n \"\r\n />\r\n <label\r\n >{{ 'catalog.use-global-value' | translate }} ({{\r\n globalOutOfStockThreshold\r\n }})</label\r\n >\r\n </clr-toggle-wrapper>\r\n </div>\r\n </div>\r\n </div>\r\n </div>\r\n <div class=\"custom-fields\">\r\n <div class=\"variant-form-input-row\">\r\n <section formGroupName=\"customFields\" *ngIf=\"customFields.length\">\r\n <vdr-tabbed-custom-fields\r\n entityName=\"ProductVariant\"\r\n [customFields]=\"customFields\"\r\n [compact]=\"true\"\r\n [customFieldsFormGroup]=\"formGroup.get('customFields')\"\r\n [readonly]=\"!(updatePermission | hasPermission)\"\r\n ></vdr-tabbed-custom-fields>\r\n </section>\r\n </div>\r\n </div>\r\n </div>\r\n </div>\r\n </div>\r\n <div class=\"card-block\">\r\n <div class=\"options-facets\">\r\n <vdr-entity-info [entity]=\"variant\"></vdr-entity-info>\r\n <div *ngIf=\"variant.options.length\">\r\n <div class=\"options\">\r\n <vdr-chip\r\n *ngFor=\"let option of variant.options | sort: 'groupId'\"\r\n [colorFrom]=\"optionGroupName(option.groupId)\"\r\n [invert]=\"true\"\r\n (iconClick)=\"editOption(option)\"\r\n [icon]=\"(updatePermission | hasPermission) && 'pencil'\"\r\n >\r\n <span class=\"option-group-name\">{{ optionGroupName(option.groupId) }}</span>\r\n {{ optionName(option) }}\r\n </vdr-chip>\r\n <a [routerLink]=\"['./', 'options']\" class=\"btn btn-link btn-sm\"\r\n >{{ 'catalog.edit-options' | translate }}...</a\r\n >\r\n </div>\r\n </div>\r\n <div class=\"flex-spacer\"></div>\r\n <div class=\"facets\">\r\n <vdr-facet-value-chip\r\n *ngFor=\"let facetValue of currentOrPendingFacetValues(variant)\"\r\n [facetValue]=\"facetValue\"\r\n [removable]=\"updatePermission | hasPermission\"\r\n (remove)=\"removeFacetValue(variant, facetValue.id)\"\r\n ></vdr-facet-value-chip>\r\n <button\r\n *vdrIfPermissions=\"updatePermission\"\r\n class=\"btn btn-sm btn-secondary\"\r\n (click)=\"selectFacetValue(variant)\"\r\n >\r\n <clr-icon shape=\"plus\"></clr-icon>\r\n {{ 'catalog.add-facets' | translate }}\r\n </button>\r\n </div>\r\n </div>\r\n </div>\r\n <ng-container *vdrIfMultichannel>\r\n <div class=\"card-block\" *vdrIfDefaultChannelActive>\r\n <div class=\"flex channel-assignment\">\r\n <ng-container *ngFor=\"let channel of variant.channels\">\r\n <vdr-chip\r\n *ngIf=\"!isDefaultChannel(channel.code)\"\r\n icon=\"times-circle\"\r\n [title]=\"'catalog.remove-from-channel' | translate: { channelCode: channel.code }\"\r\n (iconClick)=\"\r\n removeFromChannel.emit({ channelId: channel.id, variant: variant })\r\n \"\r\n >\r\n <vdr-channel-badge [channelCode]=\"channel.code\"></vdr-channel-badge>\r\n {{ channel.code | channelCodeToLabel }}\r\n </vdr-chip>\r\n </ng-container>\r\n <button class=\"btn btn-sm\" (click)=\"assignToChannel.emit(variant)\">\r\n <clr-icon shape=\"layers\"></clr-icon>\r\n {{ 'catalog.assign-to-channel' | translate }}\r\n </button>\r\n </div>\r\n </div>\r\n </ng-container>\r\n </ng-container>\r\n </div>\r\n</div>\r\n","import {\r\n ChangeDetectionStrategy,\r\n ChangeDetectorRef,\r\n Component,\r\n EventEmitter,\r\n Input,\r\n OnDestroy,\r\n OnInit,\r\n Output,\r\n} from '@angular/core';\r\nimport { FormArray, FormGroup } from '@angular/forms';\r\nimport {\r\n CustomFieldConfig,\r\n DataService,\r\n FacetValueFragment,\r\n FacetWithValuesFragment,\r\n GlobalFlag,\r\n LanguageCode,\r\n ModalService,\r\n Permission,\r\n ProductDetailFragment,\r\n ProductOptionFragment,\r\n ProductVariantFragment,\r\n TaxCategory,\r\n UpdateProductOptionInput,\r\n} from '@vendure/admin-ui/core';\r\nimport { DEFAULT_CHANNEL_CODE } from '@vendure/common/lib/shared-constants';\r\nimport { unique } from '@vendure/common/lib/unique';\r\nimport { Subscription } from 'rxjs';\r\nimport { debounceTime, distinctUntilChanged, map } from 'rxjs/operators';\r\n\r\nimport { ApplyFacetDialogComponent } from '../apply-facet-dialog/apply-facet-dialog.component';\r\nimport { AssetChange } from '../assets/assets.component';\r\nimport { PaginationConfig, SelectedAssets, VariantFormValue } from '../product-detail/product-detail.types';\r\nimport { UpdateProductOptionDialogComponent } from '../update-product-option-dialog/update-product-option-dialog.component';\r\n\r\nexport interface VariantAssetChange extends AssetChange {\r\n variantId: string;\r\n}\r\n\r\n@Component({\r\n selector: 'vdr-product-variants-list',\r\n templateUrl: './product-variants-list.component.html',\r\n styleUrls: ['./product-variants-list.component.scss'],\r\n changeDetection: ChangeDetectionStrategy.OnPush,\r\n})\r\nexport class ProductVariantsListComponent implements OnInit, OnDestroy {\r\n @Input('productVariantsFormArray') formArray: FormArray;\r\n @Input() variants: ProductVariantFragment[];\r\n @Input() paginationConfig: PaginationConfig;\r\n @Input() channelPriceIncludesTax: boolean;\r\n @Input() taxCategories: TaxCategory[];\r\n @Input() optionGroups: ProductDetailFragment['optionGroups'];\r\n @Input() customFields: CustomFieldConfig[];\r\n @Input() customOptionFields: CustomFieldConfig[];\r\n @Input() activeLanguage: LanguageCode;\r\n @Input() pendingAssetChanges: { [variantId: string]: SelectedAssets };\r\n @Input() pendingFacetValueChanges: { [variantId: string]: ProductVariantFragment['facetValues'] };\r\n @Output() assignToChannel = new EventEmitter<ProductVariantFragment>();\r\n @Output() removeFromChannel = new EventEmitter<{\r\n channelId: string;\r\n variant: ProductVariantFragment;\r\n }>();\r\n @Output() assetChange = new EventEmitter<VariantAssetChange>();\r\n @Output() selectionChange = new EventEmitter<string[]>();\r\n @Output() updateProductOption = new EventEmitter<UpdateProductOptionInput & { autoUpdate: boolean }>();\r\n selectedVariantIds: string[] = [];\r\n formGroupMap = new Map<string, FormGroup>();\r\n GlobalFlag = GlobalFlag;\r\n globalTrackInventory: boolean;\r\n globalOutOfStockThreshold: number;\r\n readonly updatePermission = [Permission.UpdateCatalog, Permission.UpdateProduct];\r\n private subscription: Subscription;\r\n\r\n constructor(\r\n private changeDetector: ChangeDetectorRef,\r\n private modalService: ModalService,\r\n private dataService: DataService,\r\n ) {}\r\n\r\n ngOnInit() {\r\n this.dataService.settings.getGlobalSettings('cache-first').single$.subscribe(({ globalSettings }) => {\r\n this.globalTrackInventory = globalSettings.trackInventory;\r\n this.globalOutOfStockThreshold = globalSettings.outOfStockThreshold;\r\n this.changeDetector.markForCheck();\r\n });\r\n this.subscription = this.formArray.valueChanges.subscribe(() => this.changeDetector.markForCheck());\r\n\r\n this.subscription.add(\r\n this.formArray.valueChanges\r\n .pipe(\r\n map(value => value.length),\r\n debounceTime(1),\r\n distinctUntilChanged(),\r\n )\r\n .subscribe(() => {\r\n this.buildFormGroupMap();\r\n }),\r\n );\r\n\r\n this.buildFormGroupMap();\r\n }\r\n\r\n ngOnDestroy() {\r\n if (this.subscription) {\r\n this.subscription.unsubscribe();\r\n }\r\n }\r\n\r\n isDefaultChannel(channelCode: string): boolean {\r\n return channelCode === DEFAULT_CHANNEL_CODE;\r\n }\r\n\r\n trackById(index: number, item: ProductVariantFragment) {\r\n return item.id;\r\n }\r\n\r\n inventoryIsNotTracked(formGroup: FormGroup): boolean {\r\n const trackInventory = formGroup.get('trackInventory')?.value;\r\n return (\r\n trackInventory === GlobalFlag.FALSE ||\r\n (trackInventory === GlobalFlag.INHERIT && this.globalTrackInventory === false)\r\n );\r\n }\r\n\r\n getTaxCategoryName(group: FormGroup): string {\r\n const control = group.get(['taxCategoryId']);\r\n if (control && this.taxCategories) {\r\n const match = this.taxCategories.find(t => t.id === control.value);\r\n return match ? match.name : '';\r\n }\r\n return '';\r\n }\r\n\r\n getStockOnHandMinValue(variant: FormGroup) {\r\n const effectiveOutOfStockThreshold = variant.get('useGlobalOutOfStockThreshold')?.value\r\n ? this.globalOutOfStockThreshold\r\n : variant.get('outOfStockThreshold')?.value;\r\n return effectiveOutOfStockThreshold;\r\n }\r\n\r\n getSaleableStockLevel(variant: ProductVariantFragment) {\r\n const effectiveOutOfStockThreshold = variant.useGlobalOutOfStockThreshold\r\n ? this.globalOutOfStockThreshold\r\n : variant.outOfStockThreshold;\r\n return variant.stockOnHand - variant.stockAllocated - effectiveOutOfStockThreshold;\r\n }\r\n\r\n areAllSelected(): boolean {\r\n return !!this.variants && this.selectedVariantIds.length === this.variants.length;\r\n }\r\n\r\n onAssetChange(variantId: string, event: AssetChange) {\r\n this.assetChange.emit({\r\n variantId,\r\n ...event,\r\n });\r\n const index = this.formArray.controls.findIndex(c => c.value.id === variantId);\r\n this.formArray.at(index).markAsDirty();\r\n }\r\n\r\n toggleSelectAll() {\r\n if (this.areAllSelected()) {\r\n this.selectedVariantIds = [];\r\n } else {\r\n this.selectedVariantIds = this.variants.map(v => v.id);\r\n }\r\n this.selectionChange.emit(this.selectedVariantIds);\r\n }\r\n\r\n toggleSelectVariant(variantId: string) {\r\n const index = this.selectedVariantIds.indexOf(variantId);\r\n if (-1 < index) {\r\n this.selectedVariantIds.splice(index, 1);\r\n } else {\r\n this.selectedVariantIds.push(variantId);\r\n }\r\n this.selectionChange.emit(this.selectedVariantIds);\r\n }\r\n\r\n optionGroupName(optionGroupId: string): string | undefined {\r\n const group = this.optionGroups.find(g => g.id === optionGroupId);\r\n if (group) {\r\n const translation =\r\n group?.translations.find(t => t.languageCode === this.activeLanguage) ??\r\n group.translations[0];\r\n return translation.name;\r\n }\r\n }\r\n\r\n optionName(option: ProductOptionFragment) {\r\n const translation =\r\n option.translations.find(t => t.languageCode === this.activeLanguage) ?? option.translations[0];\r\n return translation.name;\r\n }\r\n\r\n currentOrPendingFacetValues(variant: ProductVariantFragment) {\r\n return this.pendingFacetValueChanges[variant.id] ?? variant.facetValues;\r\n }\r\n\r\n selectFacetValue(variant: ProductVariantFragment) {\r\n return this.modalService\r\n .fromComponent(ApplyFacetDialogComponent, {\r\n size: 'md',\r\n closable: true,\r\n })\r\n .subscribe(facetValues => {\r\n if (facetValues) {\r\n const existingFacetValueIds = variant ? variant.facetValues.map(fv => fv.id) : [];\r\n const variantFormGroup = this.formArray.controls.find(c => c.value.id === variant.id);\r\n if (variantFormGroup) {\r\n const uniqueFacetValueIds = unique([\r\n ...existingFacetValueIds,\r\n ...facetValues.map(fv => fv.id),\r\n ]);\r\n variantFormGroup.patchValue({ facetValueIds: uniqueFacetValueIds });\r\n variantFormGroup.markAsDirty();\r\n if (!this.pendingFacetValueChanges[variant.id]) {\r\n this.pendingFacetValueChanges[variant.id] = variant.facetValues.slice(0);\r\n }\r\n this.pendingFacetValueChanges[variant.id].push(...facetValues);\r\n }\r\n this.changeDetector.markForCheck();\r\n }\r\n });\r\n }\r\n\r\n removeFacetValue(variant: ProductVariantFragment, facetValueId: string) {\r\n const formGroup = this.formGroupMap.get(variant.id);\r\n if (formGroup) {\r\n const newValue = (formGroup.value as VariantFormValue).facetValueIds.filter(\r\n id => id !== facetValueId,\r\n );\r\n formGroup.patchValue({\r\n facetValueIds: newValue,\r\n });\r\n formGroup.markAsDirty();\r\n if (!this.pendingFacetValueChanges[variant.id]) {\r\n this.pendingFacetValueChanges[variant.id] = variant.facetValues.slice(0);\r\n }\r\n this.pendingFacetValueChanges[variant.id] = this.pendingFacetValueChanges[variant.id].filter(\r\n fv => fv.id !== facetValueId,\r\n );\r\n }\r\n }\r\n\r\n isVariantSelected(variantId: string): boolean {\r\n return -1 < this.selectedVariantIds.indexOf(variantId);\r\n }\r\n\r\n editOption(option: ProductVariantFragment['options'][number]) {\r\n this.modalService\r\n .fromComponent(UpdateProductOptionDialogComponent, {\r\n size: 'md',\r\n locals: {\r\n productOption: option,\r\n activeLanguage: this.activeLanguage,\r\n customFields: this.customOptionFields,\r\n },\r\n })\r\n .subscribe(result => {\r\n if (result) {\r\n this.updateProductOption.emit(result);\r\n }\r\n });\r\n }\r\n\r\n private buildFormGroupMap() {\r\n this.formGroupMap.clear();\r\n for (const controlGroup of this.formArray.controls) {\r\n this.formGroupMap.set(controlGroup.value.id, controlGroup as FormGroup);\r\n }\r\n this.changeDetector.markForCheck();\r\n }\r\n\r\n private getFacetValueIds(id: string): string[] {\r\n const formValue: VariantFormValue = this.formGroupMap.get(id)?.value;\r\n return formValue.facetValueIds;\r\n }\r\n}\r\n","<vdr-action-bar>\r\n <vdr-ab-left>\r\n <div class=\"flex clr-flex-row\">\r\n <vdr-entity-info [entity]=\"entity$ | async\"></vdr-entity-info>\r\n <clr-toggle-wrapper *vdrIfPermissions=\"['UpdateCatalog', 'UpdateProduct']\">\r\n <input\r\n type=\"checkbox\"\r\n clrToggle\r\n name=\"enabled\"\r\n [formControl]=\"detailForm.get(['product', 'enabled'])\"\r\n />\r\n <label>{{ 'common.enabled' | translate }}</label>\r\n </clr-toggle-wrapper>\r\n </div>\r\n <vdr-language-selector\r\n [disabled]=\"isNew$ | async\"\r\n [availableLanguageCodes]=\"availableLanguages$ | async\"\r\n [currentLanguageCode]=\"languageCode$ | async\"\r\n (languageCodeChange)=\"setLanguage($event)\"\r\n ></vdr-language-selector>\r\n </vdr-ab-left>\r\n\r\n <vdr-ab-right>\r\n <vdr-action-bar-items locationId=\"product-detail\"></vdr-action-bar-items>\r\n <button\r\n class=\"btn btn-primary\"\r\n *ngIf=\"isNew$ | async; else updateButton\"\r\n (click)=\"create()\"\r\n [disabled]=\"detailForm.invalid || detailForm.pristine || !variantsToCreateAreValid()\"\r\n >\r\n {{ 'common.create' | translate }}\r\n </button>\r\n <ng-template #updateButton>\r\n <button\r\n *vdrIfPermissions=\"['UpdateCatalog', 'UpdateProduct']\"\r\n class=\"btn btn-primary\"\r\n (click)=\"save()\"\r\n [disabled]=\"\r\n (detailForm.invalid || detailForm.pristine) && !assetsChanged() && !variantAssetsChanged()\r\n \"\r\n >\r\n {{ 'common.update' | translate }}\r\n </button>\r\n </ng-template>\r\n </vdr-ab-right>\r\n</vdr-action-bar>\r\n\r\n<form class=\"form\" [formGroup]=\"detailForm\" *ngIf=\"product$ | async as product\">\r\n <button type=\"submit\" hidden x-data=\"prevents enter key from triggering other buttons\"></button>\r\n <clr-tabs>\r\n <clr-tab>\r\n <button clrTabLink (click)=\"navigateToTab('details')\">\r\n {{ 'catalog.product-details' | translate }}\r\n </button>\r\n <clr-tab-content *clrIfActive=\"(activeTab$ | async) === 'details'\">\r\n <div class=\"clr-row\">\r\n <div class=\"clr-col\">\r\n <section class=\"form-block\" formGroupName=\"product\">\r\n <ng-container *ngIf=\"!(isNew$ | async)\">\r\n <ng-container *vdrIfMultichannel>\r\n <vdr-form-item\r\n [label]=\"'common.channels' | translate\"\r\n *vdrIfDefaultChannelActive\r\n >\r\n <div class=\"flex channel-assignment\">\r\n <ng-container *ngFor=\"let channel of productChannels$ | async\">\r\n <vdr-chip\r\n *ngIf=\"!isDefaultChannel(channel.code)\"\r\n icon=\"times-circle\"\r\n (iconClick)=\"removeFromChannel(channel.id)\"\r\n >\r\n <vdr-channel-badge\r\n [channelCode]=\"channel.code\"\r\n ></vdr-channel-badge>\r\n {{ channel.code | channelCodeToLabel }}\r\n </vdr-chip>\r\n </ng-container>\r\n <button class=\"btn btn-sm\" (click)=\"assignToChannel()\">\r\n <clr-icon shape=\"layers\"></clr-icon>\r\n {{ 'catalog.assign-to-channel' | translate }}\r\n </button>\r\n </div>\r\n </vdr-form-item>\r\n </ng-container>\r\n </ng-container>\r\n <vdr-form-field [label]=\"'catalog.product-name' | translate\" for=\"name\">\r\n <input\r\n id=\"name\"\r\n type=\"text\"\r\n formControlName=\"name\"\r\n [readonly]=\"!(['UpdateCatalog', 'UpdateProduct'] | hasPermission)\"\r\n (input)=\"updateSlug($event.target.value)\"\r\n />\r\n </vdr-form-field>\r\n <div\r\n class=\"auto-rename-wrapper\"\r\n [class.visible]=\"\r\n (isNew$ | async) === false && detailForm.get(['product', 'name'])?.dirty\r\n \"\r\n >\r\n <clr-checkbox-wrapper>\r\n <input\r\n clrCheckbox\r\n type=\"checkbox\"\r\n id=\"auto-update\"\r\n formControlName=\"autoUpdateVariantNames\"\r\n />\r\n <label>{{\r\n 'catalog.auto-update-product-variant-name' | translate\r\n }}</label>\r\n </clr-checkbox-wrapper>\r\n </div>\r\n <vdr-form-field\r\n [label]=\"'catalog.slug' | translate\"\r\n for=\"slug\"\r\n [errors]=\"{ pattern: 'catalog.slug-pattern-error' | translate }\"\r\n >\r\n <input\r\n id=\"slug\"\r\n type=\"text\"\r\n formControlName=\"slug\"\r\n [readonly]=\"!(['UpdateCatalog', 'UpdateProduct'] | hasPermission)\"\r\n />\r\n </vdr-form-field>\r\n <vdr-rich-text-editor\r\n formControlName=\"description\"\r\n [readonly]=\"!(['UpdateCatalog', 'UpdateProduct'] | hasPermission)\"\r\n [label]=\"'common.description' | translate\"\r\n ></vdr-rich-text-editor>\r\n\r\n <section formGroupName=\"customFields\" *ngIf=\"customFields.length\">\r\n <label>{{ 'common.custom-fields' | translate }}</label>\r\n <vdr-tabbed-custom-fields\r\n entityName=\"Product\"\r\n [customFields]=\"customFields\"\r\n [customFieldsFormGroup]=\"detailForm.get(['product', 'customFields'])\"\r\n [readonly]=\"!(['UpdateCatalog', 'UpdateProduct'] | hasPermission)\"\r\n ></vdr-tabbed-custom-fields>\r\n </section>\r\n <vdr-custom-detail-component-host\r\n locationId=\"product-detail\"\r\n [entity$]=\"entity$\"\r\n [detailForm]=\"detailForm\"\r\n ></vdr-custom-detail-component-host>\r\n </section>\r\n </div>\r\n <div class=\"clr-col-md-auto\">\r\n <vdr-assets\r\n [assets]=\"assetChanges.assets || product.assets\"\r\n [featuredAsset]=\"assetChanges.featuredAsset || product.featuredAsset\"\r\n [updatePermissions]=\"updatePermissions\"\r\n (change)=\"assetChanges = $event\"\r\n ></vdr-assets>\r\n <div class=\"facets\">\r\n <vdr-facet-value-chip\r\n *ngFor=\"let facetValue of facetValues$ | async\"\r\n [facetValue]=\"facetValue\"\r\n [removable]=\"['UpdateCatalog', 'UpdateProduct'] | hasPermission\"\r\n (remove)=\"removeProductFacetValue(facetValue.id)\"\r\n ></vdr-facet-value-chip>\r\n <button\r\n class=\"btn btn-sm btn-secondary\"\r\n *vdrIfPermissions=\"['UpdateCatalog', 'UpdateProduct']\"\r\n (click)=\"selectProductFacetValue()\"\r\n >\r\n <clr-icon shape=\"plus\"></clr-icon>\r\n {{ 'catalog.add-facets' | translate }}\r\n </button>\r\n </div>\r\n </div>\r\n </div>\r\n\r\n <div *ngIf=\"isNew$ | async\">\r\n <h4>{{ 'catalog.product-variants' | translate }}</h4>\r\n <vdr-generate-product-variants\r\n (variantsChange)=\"createVariantsConfig = $event\"\r\n ></vdr-generate-product-variants>\r\n </div>\r\n </clr-tab-content>\r\n </clr-tab>\r\n <clr-tab *ngIf=\"!(isNew$ | async)\">\r\n <button clrTabLink (click)=\"navigateToTab('variants')\">\r\n {{ 'catalog.product-variants' | translate }}\r\n </button>\r\n <clr-tab-content *clrIfActive=\"(activeTab$ | async) === 'variants'\">\r\n <section class=\"form-block\">\r\n <div class=\"view-mode\">\r\n <div class=\"btn-group\">\r\n <button\r\n class=\"btn btn-secondary-outline\"\r\n (click)=\"variantDisplayMode = 'card'\"\r\n [class.btn-primary]=\"variantDisplayMode === 'card'\"\r\n >\r\n <clr-icon shape=\"list\"></clr-icon>\r\n <span class=\"full-label\">{{ 'catalog.display-variant-cards' | translate }}</span>\r\n </button>\r\n <button\r\n class=\"btn\"\r\n (click)=\"variantDisplayMode = 'table'\"\r\n [class.btn-primary]=\"variantDisplayMode === 'table'\"\r\n >\r\n <clr-icon shape=\"table\"></clr-icon>\r\n <span class=\"full-label\">{{ 'catalog.display-variant-table' | translate }}</span>\r\n </button>\r\n </div>\r\n <div class=\"variant-filter\">\r\n <input\r\n [formControl]=\"filterInput\"\r\n [placeholder]=\"'catalog.filter-by-name-or-sku' | translate\"\r\n />\r\n <button class=\"icon-button\" (click)=\"filterInput.setValue('')\">\r\n <clr-icon shape=\"times\"></clr-icon>\r\n </button>\r\n </div>\r\n <div class=\"flex-spacer\"></div>\r\n <a\r\n *vdrIfPermissions=\"['UpdateCatalog', 'UpdateProduct']\"\r\n [routerLink]=\"['./', 'manage-variants']\"\r\n class=\"btn btn-secondary edit-variants-btn mb0 mr0\"\r\n >\r\n <clr-icon shape=\"add-text\"></clr-icon>\r\n {{ 'catalog.manage-variants' | translate }}\r\n </a>\r\n </div>\r\n\r\n <div class=\"pagination-row mt4\" *ngIf=\"10 < (paginationConfig$ | async)?.totalItems\">\r\n <vdr-items-per-page-controls\r\n [itemsPerPage]=\"itemsPerPage$ | async\"\r\n (itemsPerPageChange)=\"setItemsPerPage($event)\"\r\n ></vdr-items-per-page-controls>\r\n\r\n <vdr-pagination-controls\r\n [id]=\"(paginationConfig$ | async)?.id\"\r\n [currentPage]=\"currentPage$ | async\"\r\n [itemsPerPage]=\"itemsPerPage$ | async\"\r\n (pageChange)=\"setPage($event)\"\r\n ></vdr-pagination-controls>\r\n </div>\r\n\r\n <vdr-product-variants-table\r\n *ngIf=\"variantDisplayMode === 'table'\"\r\n [variants]=\"variants$ | async\"\r\n [paginationConfig]=\"paginationConfig$ | async\"\r\n [optionGroups]=\"product.optionGroups\"\r\n [channelPriceIncludesTax]=\"channelPriceIncludesTax$ | async\"\r\n [productVariantsFormArray]=\"detailForm.get('variants')\"\r\n [pendingAssetChanges]=\"variantAssetChanges\"\r\n ></vdr-product-variants-table>\r\n <vdr-product-variants-list\r\n *ngIf=\"variantDisplayMode === 'card'\"\r\n [variants]=\"variants$ | async\"\r\n [paginationConfig]=\"paginationConfig$ | async\"\r\n [channelPriceIncludesTax]=\"channelPriceIncludesTax$ | async\"\r\n [pendingFacetValueChanges]=\"variantFacetValueChanges\"\r\n [optionGroups]=\"product.optionGroups\"\r\n [productVariantsFormArray]=\"detailForm.get('variants')\"\r\n [taxCategories]=\"taxCategories$ | async\"\r\n [customFields]=\"customVariantFields\"\r\n [customOptionFields]=\"customOptionFields\"\r\n [activeLanguage]=\"languageCode$ | async\"\r\n [pendingAssetChanges]=\"variantAssetChanges\"\r\n (assignToChannel)=\"assignVariantToChannel($event)\"\r\n (removeFromChannel)=\"removeVariantFromChannel($event)\"\r\n (assetChange)=\"variantAssetChange($event)\"\r\n (updateProductOption)=\"updateProductOption($event)\"\r\n (selectionChange)=\"selectedVariantIds = $event\"\r\n ></vdr-product-variants-list>\r\n </section>\r\n <div class=\"pagination-row mt4\" *ngIf=\"10 < (paginationConfig$ | async)?.totalItems\">\r\n <vdr-items-per-page-controls\r\n [itemsPerPage]=\"itemsPerPage$ | async\"\r\n (itemsPerPageChange)=\"setItemsPerPage($event)\"\r\n ></vdr-items-per-page-controls>\r\n\r\n <vdr-pagination-controls\r\n [id]=\"(paginationConfig$ | async)?.id\"\r\n [currentPage]=\"currentPage$ | async\"\r\n [itemsPerPage]=\"itemsPerPage$ | async\"\r\n (pageChange)=\"setPage($event)\"\r\n ></vdr-pagination-controls>\r\n </div>\r\n </clr-tab-content>\r\n </clr-tab>\r\n </clr-tabs>\r\n</form>\r\n","import { Location } from '@angular/common';\r\nimport { ChangeDetectionStrategy, ChangeDetectorRef, Component, OnDestroy, OnInit } from '@angular/core';\r\nimport { FormArray, FormBuilder, FormControl, FormGroup, Validators } from '@angular/forms';\r\nimport { ActivatedRoute, Router } from '@angular/router';\r\nimport { marker as _ } from '@biesbjerg/ngx-translate-extract-marker';\r\nimport {\r\n BaseDetailComponent,\r\n CreateProductInput,\r\n createUpdatedTranslatable,\r\n CustomFieldConfig,\r\n DataService,\r\n findTranslation,\r\n getChannelCodeFromUserStatus,\r\n GetProductWithVariantsQuery,\r\n LanguageCode,\r\n LogicalOperator,\r\n ModalService,\r\n NotificationService,\r\n Permission,\r\n ProductDetailFragment,\r\n ProductVariantFragment,\r\n ServerConfigService,\r\n TaxCategoryFragment,\r\n unicodePatternValidator,\r\n UpdateProductInput,\r\n UpdateProductMutation,\r\n UpdateProductOptionInput,\r\n UpdateProductVariantInput,\r\n UpdateProductVariantsMutation,\r\n} from '@vendure/admin-ui/core';\r\nimport { normalizeString } from '@vendure/common/lib/normalize-string';\r\nimport { DEFAULT_CHANNEL_CODE } from '@vendure/common/lib/shared-constants';\r\nimport { notNullOrUndefined } from '@vendure/common/lib/shared-utils';\r\nimport { unique } from '@vendure/common/lib/unique';\r\nimport { BehaviorSubject, combineLatest, concat, EMPTY, from, merge, Observable } from 'rxjs';\r\nimport {\r\n debounceTime,\r\n distinctUntilChanged,\r\n map,\r\n mergeMap,\r\n shareReplay,\r\n skip,\r\n skipUntil,\r\n startWith,\r\n switchMap,\r\n switchMapTo,\r\n take,\r\n takeUntil,\r\n tap,\r\n} from 'rxjs/operators';\r\n\r\nimport { ProductDetailService } from '../../providers/product-detail/product-detail.service';\r\nimport { ApplyFacetDialogComponent } from '../apply-facet-dialog/apply-facet-dialog.component';\r\nimport { AssignProductsToChannelDialogComponent } from '../assign-products-to-channel-dialog/assign-products-to-channel-dialog.component';\r\nimport { CreateProductVariantsConfig } from '../generate-product-variants/generate-product-variants.component';\r\nimport { VariantAssetChange } from '../product-variants-list/product-variants-list.component';\r\n\r\nimport { PaginationConfig, SelectedAssets, TabName, VariantFormValue } from './product-detail.types';\r\n\r\n@Component({\r\n selector: 'vdr-product-detail',\r\n templateUrl: './product-detail.component.html',\r\n styleUrls: ['./product-detail.component.scss'],\r\n changeDetection: ChangeDetectionStrategy.OnPush,\r\n})\r\nexport class ProductDetailComponent\r\n extends BaseDetailComponent<NonNullable<GetProductWithVariantsQuery['product']>>\r\n implements OnInit, OnDestroy\r\n{\r\n activeTab$: Observable<TabName>;\r\n product$: Observable<NonNullable<GetProductWithVariantsQuery['product']>>;\r\n variants$: Observable<ProductVariantFragment[]>;\r\n taxCategories$: Observable<TaxCategoryFragment[]>;\r\n customFields: CustomFieldConfig[];\r\n customVariantFields: CustomFieldConfig[];\r\n customOptionGroupFields: CustomFieldConfig[];\r\n customOptionFields: CustomFieldConfig[];\r\n detailForm: FormGroup;\r\n filterInput = new FormControl('');\r\n assetChanges: SelectedAssets = {};\r\n variantAssetChanges: { [variantId: string]: SelectedAssets } = {};\r\n variantFacetValueChanges: { [variantId: string]: ProductVariantFragment['facetValues'] } = {};\r\n productChannels$: Observable<ProductDetailFragment['channels']>;\r\n facetValues$: Observable<ProductDetailFragment['facetValues']>;\r\n totalItems$: Observable<number>;\r\n currentPage$ = new BehaviorSubject(1);\r\n itemsPerPage$ = new BehaviorSubject(10);\r\n paginationConfig$: Observable<PaginationConfig>;\r\n selectedVariantIds: string[] = [];\r\n variantDisplayMode: 'card' | 'table' = 'card';\r\n createVariantsConfig: CreateProductVariantsConfig = { groups: [], variants: [] };\r\n channelPriceIncludesTax$: Observable<boolean>;\r\n // Used to store all ProductVariants which have been loaded.\r\n // It is needed when saving changes to variants.\r\n private productVariantMap = new Map<string, ProductVariantFragment>();\r\n public readonly updatePermissions = [Permission.UpdateCatalog, Permission.UpdateProduct];\r\n\r\n constructor(\r\n route: ActivatedRoute,\r\n router: Router,\r\n serverConfigService: ServerConfigService,\r\n private productDetailService: ProductDetailService,\r\n private formBuilder: FormBuilder,\r\n private modalService: ModalService,\r\n private notificationService: NotificationService,\r\n protected dataService: DataService,\r\n private location: Location,\r\n private changeDetector: ChangeDetectorRef,\r\n ) {\r\n super(route, router, serverConfigService, dataService);\r\n this.customFields = this.getCustomFieldConfig('Product');\r\n this.customVariantFields = this.getCustomFieldConfig('ProductVariant');\r\n this.customOptionGroupFields = this.getCustomFieldConfig('ProductOptionGroup');\r\n this.customOptionFields = this.getCustomFieldConfig('ProductOption');\r\n this.detailForm = this.formBuilder.group({\r\n product: this.formBuilder.group({\r\n enabled: true,\r\n name: ['', Validators.required],\r\n autoUpdateVariantNames: true,\r\n slug: ['', unicodePatternValidator(/^[\\p{Letter}0-9_-]+$/)],\r\n description: '',\r\n facetValueIds: [[]],\r\n customFields: this.formBuilder.group(\r\n this.customFields.reduce((hash, field) => ({ ...hash, [field.name]: '' }), {}),\r\n ),\r\n }),\r\n variants: this.formBuilder.array([]),\r\n });\r\n }\r\n\r\n ngOnInit() {\r\n this.init();\r\n this.product$ = this.entity$;\r\n const filterTerm$ = this.filterInput.valueChanges.pipe(\r\n startWith(''),\r\n debounceTime(200),\r\n shareReplay(),\r\n tap(() => this.currentPage$.next(1)),\r\n );\r\n const initialVariants$ = this.product$.pipe(map(p => p.variantList.items));\r\n const variantsList$ = combineLatest(filterTerm$, this.currentPage$, this.itemsPerPage$).pipe(\r\n skipUntil(initialVariants$),\r\n skip(1),\r\n debounceTime(100),\r\n switchMap(([term, currentPage, itemsPerPage]) => {\r\n return this.dataService.product\r\n .getProductVariants(\r\n {\r\n skip: (currentPage - 1) * itemsPerPage,\r\n take: itemsPerPage,\r\n ...(term\r\n ? { filter: { name: { contains: term }, sku: { contains: term } } }\r\n : {}),\r\n filterOperator: LogicalOperator.OR,\r\n },\r\n this.id,\r\n )\r\n .mapStream(({ productVariants }) => productVariants);\r\n }),\r\n shareReplay({ bufferSize: 1, refCount: true }),\r\n );\r\n const updatedVariants$ = variantsList$.pipe(map(result => result.items));\r\n this.variants$ = merge(initialVariants$, updatedVariants$).pipe(\r\n tap(variants => {\r\n for (const variant of variants) {\r\n this.productVariantMap.set(variant.id, variant);\r\n }\r\n }),\r\n );\r\n this.totalItems$ = merge(\r\n this.product$.pipe(map(product => product.variantList.totalItems)),\r\n variantsList$.pipe(map(result => result.totalItems)),\r\n );\r\n this.paginationConfig$ = combineLatest(this.totalItems$, this.itemsPerPage$, this.currentPage$).pipe(\r\n map(([totalItems, itemsPerPage, currentPage]) => ({\r\n totalItems,\r\n itemsPerPage,\r\n currentPage,\r\n })),\r\n );\r\n this.taxCategories$ = this.productDetailService.getTaxCategories().pipe(takeUntil(this.destroy$));\r\n this.activeTab$ = this.route.paramMap.pipe(map(qpm => qpm.get('tab') as any));\r\n\r\n combineLatest(updatedVariants$, this.languageCode$)\r\n .pipe(takeUntil(this.destroy$))\r\n .subscribe(([variants, languageCode]) => {\r\n this.buildVariantFormArray(variants, languageCode);\r\n });\r\n\r\n const productFacetValues$ = this.product$.pipe(map(product => product.facetValues));\r\n const productGroup = this.getProductFormGroup();\r\n // tslint:disable-next-line:no-non-null-assertion\r\n const formFacetValueIdChanges$ = productGroup.get('facetValueIds')!.valueChanges.pipe(\r\n skip(1),\r\n distinctUntilChanged(),\r\n switchMap(ids =>\r\n this.dataService.facet\r\n .getFacetValues({ filter: { id: { in: ids } } })\r\n .mapSingle(({ facetValues }) => facetValues.items),\r\n ),\r\n shareReplay(1),\r\n );\r\n this.facetValues$ = concat(\r\n productFacetValues$.pipe(take(1)),\r\n productFacetValues$.pipe(switchMapTo(formFacetValueIdChanges$)),\r\n );\r\n this.productChannels$ = this.product$.pipe(map(p => p.channels));\r\n this.channelPriceIncludesTax$ = this.dataService.settings\r\n .getActiveChannel('cache-first')\r\n .refetchOnChannelChange()\r\n .mapStream(data => data.activeChannel.pricesIncludeTax)\r\n .pipe(shareReplay(1));\r\n }\r\n\r\n ngOnDestroy() {\r\n this.destroy();\r\n }\r\n\r\n navigateToTab(tabName: TabName) {\r\n this.location.replaceState(\r\n this.router\r\n .createUrlTree(['./', { ...this.route.snapshot.params, tab: tabName }], {\r\n queryParamsHandling: 'merge',\r\n relativeTo: this.route,\r\n })\r\n .toString(),\r\n );\r\n }\r\n\r\n isDefaultChannel(channelCode: string): boolean {\r\n return channelCode === DEFAULT_CHANNEL_CODE;\r\n }\r\n\r\n setPage(page: number) {\r\n this.currentPage$.next(page);\r\n }\r\n\r\n setItemsPerPage(value: string) {\r\n this.itemsPerPage$.next(+value);\r\n this.currentPage$.next(1);\r\n }\r\n\r\n assignToChannel() {\r\n this.productChannels$\r\n .pipe(\r\n take(1),\r\n switchMap(channels => {\r\n return this.modalService.fromComponent(AssignProductsToChannelDialogComponent, {\r\n size: 'lg',\r\n locals: {\r\n productIds: [this.id],\r\n currentChannelIds: channels.map(c => c.id),\r\n },\r\n });\r\n }),\r\n )\r\n .subscribe();\r\n }\r\n\r\n removeFromChannel(channelId: string) {\r\n from(getChannelCodeFromUserStatus(this.dataService, channelId))\r\n .pipe(\r\n switchMap(({ channelCode }) => {\r\n return this.modalService.dialog({\r\n title: _('catalog.remove-product-from-channel'),\r\n buttons: [\r\n { type: 'secondary', label: _('common.cancel') },\r\n {\r\n type: 'danger',\r\n label: _('catalog.remove-from-channel'),\r\n translationVars: { channelCode },\r\n returnValue: true,\r\n },\r\n ],\r\n });\r\n }),\r\n switchMap(response =>\r\n response\r\n ? this.dataService.product.removeProductsFromChannel({\r\n channelId,\r\n productIds: [this.id],\r\n })\r\n : EMPTY,\r\n ),\r\n )\r\n .subscribe(\r\n () => {\r\n this.notificationService.success(_('catalog.notify-remove-product-from-channel-success'));\r\n },\r\n err => {\r\n this.notificationService.error(_('catalog.notify-remove-product-from-channel-error'));\r\n },\r\n );\r\n }\r\n\r\n assignVariantToChannel(variant: ProductVariantFragment) {\r\n return this.modalService\r\n .fromComponent(AssignProductsToChannelDialogComponent, {\r\n size: 'lg',\r\n locals: {\r\n productIds: [this.id],\r\n productVariantIds: [variant.id],\r\n currentChannelIds: variant.channels.map(c => c.id),\r\n },\r\n })\r\n .subscribe();\r\n }\r\n\r\n removeVariantFromChannel({ channelId, variant }: { channelId: string; variant: ProductVariantFragment }) {\r\n from(getChannelCodeFromUserStatus(this.dataService, channelId))\r\n .pipe(\r\n switchMap(({ channelCode }) => {\r\n return this.modalService.dialog({\r\n title: _('catalog.remove-product-variant-from-channel'),\r\n buttons: [\r\n { type: 'secondary', label: _('common.cancel') },\r\n {\r\n type: 'danger',\r\n label: _('catalog.remove-from-channel'),\r\n translationVars: { channelCode },\r\n returnValue: true,\r\n },\r\n ],\r\n });\r\n }),\r\n switchMap(response =>\r\n response\r\n ? this.dataService.product.removeVariantsFromChannel({\r\n channelId,\r\n productVariantIds: [variant.id],\r\n })\r\n : EMPTY,\r\n ),\r\n )\r\n .subscribe(\r\n () => {\r\n this.notificationService.success(_('catalog.notify-remove-variant-from-channel-success'));\r\n },\r\n err => {\r\n this.notificationService.error(_('catalog.notify-remove-variant-from-channel-error'));\r\n },\r\n );\r\n }\r\n\r\n assetsChanged(): boolean {\r\n return !!Object.values(this.assetChanges).length;\r\n }\r\n\r\n variantAssetsChanged(): boolean {\r\n return !!Object.keys(this.variantAssetChanges).length;\r\n }\r\n\r\n variantAssetChange(event: VariantAssetChange) {\r\n this.variantAssetChanges[event.variantId] = event;\r\n }\r\n\r\n /**\r\n * If creating a new product, automatically generate the slug based on the product name.\r\n */\r\n updateSlug(nameValue: string) {\r\n combineLatest(this.entity$, this.languageCode$)\r\n .pipe(take(1))\r\n .subscribe(([entity, languageCode]) => {\r\n const slugControl = this.detailForm.get(['product', 'slug']);\r\n const currentTranslation = findTranslation(entity, languageCode);\r\n const currentSlugIsEmpty = !currentTranslation || !currentTranslation.slug;\r\n if (slugControl && slugControl.pristine && currentSlugIsEmpty) {\r\n slugControl.setValue(normalizeString(`${nameValue}`, '-'));\r\n }\r\n });\r\n }\r\n\r\n selectProductFacetValue() {\r\n this.displayFacetValueModal().subscribe(facetValueIds => {\r\n if (facetValueIds) {\r\n const productGroup = this.getProductFormGroup();\r\n const currentFacetValueIds = productGroup.value.facetValueIds;\r\n productGroup.patchValue({\r\n facetValueIds: unique([...currentFacetValueIds, ...facetValueIds]),\r\n });\r\n productGroup.markAsDirty();\r\n }\r\n });\r\n }\r\n\r\n updateProductOption(input: UpdateProductOptionInput & { autoUpdate: boolean }) {\r\n combineLatest(this.product$, this.languageCode$)\r\n .pipe(\r\n take(1),\r\n mergeMap(([product, languageCode]) =>\r\n this.productDetailService.updateProductOption(input, product, languageCode),\r\n ),\r\n )\r\n .subscribe(\r\n () => {\r\n this.notificationService.success(_('common.notify-update-success'), {\r\n entity: 'ProductOption',\r\n });\r\n },\r\n err => {\r\n this.notificationService.error(_('common.notify-update-error'), {\r\n entity: 'ProductOption',\r\n });\r\n },\r\n );\r\n }\r\n\r\n removeProductFacetValue(facetValueId: string) {\r\n const productGroup = this.getProductFormGroup();\r\n const currentFacetValueIds = productGroup.value.facetValueIds;\r\n productGroup.patchValue({\r\n facetValueIds: currentFacetValueIds.filter(id => id !== facetValueId),\r\n });\r\n productGroup.markAsDirty();\r\n }\r\n\r\n variantsToCreateAreValid(): boolean {\r\n return (\r\n 0 < this.createVariantsConfig.variants.length &&\r\n this.createVariantsConfig.variants.every(v => {\r\n return v.sku !== '';\r\n })\r\n );\r\n }\r\n\r\n private displayFacetValueModal(): Observable<string[] | undefined> {\r\n return this.modalService\r\n .fromComponent(ApplyFacetDialogComponent, {\r\n size: 'md',\r\n closable: true,\r\n })\r\n .pipe(map(facetValues => facetValues && facetValues.map(v => v.id)));\r\n }\r\n\r\n create() {\r\n const productGroup = this.getProductFormGroup();\r\n if (!productGroup.dirty) {\r\n return;\r\n }\r\n combineLatest(this.product$, this.languageCode$)\r\n .pipe(\r\n take(1),\r\n mergeMap(([product, languageCode]) => {\r\n const newProduct = this.getUpdatedProduct(\r\n product,\r\n productGroup as FormGroup,\r\n languageCode,\r\n ) as CreateProductInput;\r\n return this.productDetailService.createProductWithVariants(\r\n newProduct,\r\n this.createVariantsConfig,\r\n languageCode,\r\n );\r\n }),\r\n )\r\n .subscribe(\r\n ({ createProductVariants, productId }) => {\r\n this.notificationService.success(_('common.notify-create-success'), {\r\n entity: 'Product',\r\n });\r\n this.assetChanges = {};\r\n this.variantAssetChanges = {};\r\n this.detailForm.markAsPristine();\r\n this.router.navigate(['../', productId], { relativeTo: this.route });\r\n },\r\n err => {\r\n // tslint:disable-next-line:no-console\r\n console.error(err);\r\n this.notificationService.error(_('common.notify-create-error'), {\r\n entity: 'Product',\r\n });\r\n },\r\n );\r\n }\r\n\r\n save() {\r\n combineLatest(this.product$, this.languageCode$, this.channelPriceIncludesTax$)\r\n .pipe(\r\n take(1),\r\n mergeMap(([product, languageCode, priceIncludesTax]) => {\r\n const productGroup = this.getProductFormGroup();\r\n let productInput: UpdateProductInput | undefined;\r\n let variantsInput: UpdateProductVariantInput[] | undefined;\r\n\r\n if (productGroup.dirty || this.assetsChanged()) {\r\n productInput = this.getUpdatedProduct(\r\n product,\r\n productGroup as FormGroup,\r\n languageCode,\r\n ) as UpdateProductInput;\r\n }\r\n const variantsArray = this.detailForm.get('variants');\r\n if ((variantsArray && variantsArray.dirty) || this.variantAssetsChanged()) {\r\n variantsInput = this.getUpdatedProductVariants(\r\n product,\r\n variantsArray as FormArray,\r\n languageCode,\r\n priceIncludesTax,\r\n );\r\n }\r\n\r\n return this.productDetailService.updateProduct({\r\n product,\r\n languageCode,\r\n autoUpdate:\r\n this.detailForm.get(['product', 'autoUpdateVariantNames'])?.value ?? false,\r\n productInput,\r\n variantsInput,\r\n });\r\n }),\r\n )\r\n .subscribe(\r\n result => {\r\n this.updateSlugAfterSave(result);\r\n this.detailForm.markAsPristine();\r\n this.assetChanges = {};\r\n this.variantAssetChanges = {};\r\n this.variantFacetValueChanges = {};\r\n this.notificationService.success(_('common.notify-update-success'), {\r\n entity: 'Product',\r\n });\r\n this.changeDetector.markForCheck();\r\n },\r\n err => {\r\n this.notificationService.error(_('common.notify-update-error'), {\r\n entity: 'Product',\r\n });\r\n },\r\n );\r\n }\r\n\r\n canDeactivate(): boolean {\r\n return super.canDeactivate() && !this.assetChanges.assets && !this.assetChanges.featuredAsset;\r\n }\r\n\r\n /**\r\n * Sets the values of the form on changes to the product or current language.\r\n */\r\n protected setFormValues(\r\n product: NonNullable<GetProductWithVariantsQuery['product']>,\r\n languageCode: LanguageCode,\r\n ) {\r\n const currentTranslation = findTranslation(product, languageCode);\r\n this.detailForm.patchValue({\r\n product: {\r\n enabled: product.enabled,\r\n name: currentTranslation ? currentTranslation.name : '',\r\n slug: currentTranslation ? currentTranslation.slug : '',\r\n description: currentTranslation ? currentTranslation.description : '',\r\n facetValueIds: product.facetValues.map(fv => fv.id),\r\n },\r\n });\r\n\r\n if (this.customFields.length) {\r\n this.setCustomFieldFormValues(\r\n this.customFields,\r\n this.detailForm.get(['product', 'customFields']),\r\n product,\r\n currentTranslation,\r\n );\r\n }\r\n this.buildVariantFormArray(product.variantList.items, languageCode);\r\n }\r\n\r\n private buildVariantFormArray(variants: ProductVariantFragment[], languageCode: LanguageCode) {\r\n const variantsFormArray = this.detailForm.get('variants') as FormArray;\r\n variants.forEach((variant, i) => {\r\n const variantTranslation = findTranslation(variant, languageCode);\r\n const pendingFacetValueChanges = this.variantFacetValueChanges[variant.id];\r\n const facetValueIds = pendingFacetValueChanges\r\n ? pendingFacetValueChanges.map(fv => fv.id)\r\n : variant.facetValues.map(fv => fv.id);\r\n const group: VariantFormValue = {\r\n id: variant.id,\r\n enabled: variant.enabled,\r\n sku: variant.sku,\r\n name: variantTranslation ? variantTranslation.name : '',\r\n price: variant.price,\r\n priceWithTax: variant.priceWithTax,\r\n taxCategoryId: variant.taxCategory.id,\r\n stockOnHand: variant.stockOnHand,\r\n useGlobalOutOfStockThreshold: variant.useGlobalOutOfStockThreshold,\r\n outOfStockThreshold: variant.outOfStockThreshold,\r\n trackInventory: variant.trackInventory,\r\n facetValueIds,\r\n };\r\n\r\n let variantFormGroup = variantsFormArray.controls.find(c => c.value.id === variant.id) as\r\n | FormGroup\r\n | undefined;\r\n if (variantFormGroup) {\r\n if (variantFormGroup.pristine) {\r\n variantFormGroup.patchValue(group);\r\n }\r\n } else {\r\n variantFormGroup = this.formBuilder.group({\r\n ...group,\r\n facetValueIds: this.formBuilder.control(facetValueIds),\r\n });\r\n variantsFormArray.insert(i, variantFormGroup);\r\n }\r\n if (this.customVariantFields.length) {\r\n let customFieldsGroup = variantFormGroup.get(['customFields']) as FormGroup | undefined;\r\n\r\n if (!customFieldsGroup) {\r\n customFieldsGroup = this.formBuilder.group(\r\n this.customVariantFields.reduce((hash, field) => ({ ...hash, [field.name]: '' }), {}),\r\n );\r\n variantFormGroup.addControl('customFields', customFieldsGroup);\r\n }\r\n this.setCustomFieldFormValues(\r\n this.customVariantFields,\r\n customFieldsGroup,\r\n variant,\r\n variantTranslation,\r\n );\r\n }\r\n });\r\n }\r\n\r\n /**\r\n * Given a product and the value of the detailForm, this method creates an updated copy of the product which\r\n * can then be persisted to the API.\r\n */\r\n private getUpdatedProduct(\r\n product: NonNullable<GetProductWithVariantsQuery['product']>,\r\n productFormGroup: FormGroup,\r\n languageCode: LanguageCode,\r\n ): UpdateProductInput | CreateProductInput {\r\n const updatedProduct = createUpdatedTranslatable({\r\n translatable: product,\r\n updatedFields: productFormGroup.value,\r\n customFieldConfig: this.customFields,\r\n languageCode,\r\n defaultTranslation: {\r\n languageCode,\r\n name: product.name || '',\r\n slug: product.slug || '',\r\n description: product.description || '',\r\n },\r\n });\r\n return {\r\n ...updatedProduct,\r\n assetIds: this.assetChanges.assets?.map(a => a.id),\r\n featuredAssetId: this.assetChanges.featuredAsset?.id,\r\n facetValueIds: productFormGroup.value.facetValueIds,\r\n } as UpdateProductInput | CreateProductInput;\r\n }\r\n\r\n /**\r\n * Given an array of product variants and the values from the detailForm, this method creates an new array\r\n * which can be persisted to the API.\r\n */\r\n private getUpdatedProductVariants(\r\n product: NonNullable<GetProductWithVariantsQuery['product']>,\r\n variantsFormArray: FormArray,\r\n languageCode: LanguageCode,\r\n priceIncludesTax: boolean,\r\n ): UpdateProductVariantInput[] {\r\n const dirtyFormControls = variantsFormArray.controls.filter(c => c.dirty);\r\n const dirtyVariants = dirtyFormControls\r\n .map(c => this.productVariantMap.get(c.value.id))\r\n .filter(notNullOrUndefined);\r\n const dirtyVariantValues = dirtyFormControls.map(c => c.value);\r\n\r\n if (dirtyVariants.length !== dirtyVariantValues.length) {\r\n throw new Error(_(`error.product-variant-form-values-do-not-match`));\r\n }\r\n return dirtyVariants\r\n .map((variant, i) => {\r\n const formValue: VariantFormValue = dirtyVariantValues.find(value => value.id === variant.id);\r\n const result: UpdateProductVariantInput = createUpdatedTranslatable({\r\n translatable: variant,\r\n updatedFields: formValue,\r\n customFieldConfig: this.customVariantFields,\r\n languageCode,\r\n defaultTranslation: {\r\n languageCode,\r\n name: '',\r\n },\r\n });\r\n result.taxCategoryId = formValue.taxCategoryId;\r\n result.facetValueIds = formValue.facetValueIds;\r\n result.price = priceIncludesTax ? formValue.priceWithTax : formValue.price;\r\n const assetChanges = this.variantAssetChanges[variant.id];\r\n if (assetChanges) {\r\n result.featuredAssetId = assetChanges.featuredAsset?.id;\r\n result.assetIds = assetChanges.assets?.map(a => a.id);\r\n }\r\n return result;\r\n })\r\n .filter(notNullOrUndefined);\r\n }\r\n\r\n private getProductFormGroup(): FormGroup {\r\n return this.detailForm.get('product') as FormGroup;\r\n }\r\n\r\n /**\r\n * The server may alter the slug value in order to normalize and ensure uniqueness upon saving.\r\n */\r\n private updateSlugAfterSave(results: Array<UpdateProductMutation | UpdateProductVariantsMutation>) {\r\n const firstResult = results[0];\r\n const slugControl = this.detailForm.get(['product', 'slug']);\r\n\r\n function isUpdateMutation(input: any): input is UpdateProductMutation {\r\n return input.hasOwnProperty('updateProduct');\r\n }\r\n\r\n if (slugControl && isUpdateMutation(firstResult)) {\r\n slugControl.setValue(firstResult.updateProduct.slug, { emitEvent: false });\r\n }\r\n }\r\n}\r\n","<vdr-action-bar>\r\n <vdr-ab-left [grow]=\"true\">\r\n <div class=\"search-form\">\r\n <vdr-product-search-input\r\n #productSearchInputComponent\r\n [facetValueResults]=\"facetValues$ | async\"\r\n (searchTermChange)=\"setSearchTerm($event)\"\r\n (facetValueChange)=\"setFacetValueIds($event)\"\r\n ></vdr-product-search-input>\r\n <vdr-dropdown class=\"search-settings-menu mr3\">\r\n <button\r\n type=\"button\"\r\n class=\"icon-button search-index-button\"\r\n [title]=\"\r\n (pendingSearchIndexUpdates\r\n ? 'catalog.pending-search-index-updates'\r\n : 'catalog.search-index-controls'\r\n ) | translate\r\n \"\r\n vdrDropdownTrigger\r\n >\r\n <clr-icon shape=\"cog\"></clr-icon>\r\n <vdr-status-badge *ngIf=\"pendingSearchIndexUpdates\" type=\"warning\"></vdr-status-badge>\r\n </button>\r\n <vdr-dropdown-menu vdrPosition=\"bottom-right\">\r\n <h4 class=\"dropdown-header\">{{ 'catalog.search-index-controls' | translate }}</h4>\r\n <ng-container *ngIf=\"pendingSearchIndexUpdates\">\r\n <button\r\n type=\"button\"\r\n class=\"run-updates-button\"\r\n vdrDropdownItem\r\n (click)=\"runPendingSearchIndexUpdates()\"\r\n [disabled]=\"!(['UpdateCatalog', 'UpdateProduct'] | hasPermission)\"\r\n >\r\n <vdr-status-badge type=\"warning\"></vdr-status-badge>\r\n {{\r\n 'catalog.run-pending-search-index-updates'\r\n | translate: { count: pendingSearchIndexUpdates }\r\n }}\r\n </button>\r\n <div class=\"dropdown-divider\"></div>\r\n </ng-container>\r\n <button\r\n type=\"button\"\r\n vdrDropdownItem\r\n (click)=\"rebuildSearchIndex()\"\r\n [disabled]=\"!(['UpdateCatalog', 'UpdateProduct'] | hasPermission)\"\r\n >\r\n {{ 'catalog.rebuild-search-index' | translate }}\r\n </button>\r\n </vdr-dropdown-menu>\r\n </vdr-dropdown>\r\n </div>\r\n <div class=\"flex wrap\">\r\n <clr-toggle-wrapper class=\"mt2\">\r\n <input type=\"checkbox\" clrToggle [(ngModel)]=\"groupByProduct\" (ngModelChange)=\"refresh()\" />\r\n <label>\r\n {{ 'catalog.group-by-product' | translate }}\r\n </label>\r\n </clr-toggle-wrapper>\r\n <vdr-language-selector\r\n [availableLanguageCodes]=\"availableLanguages$ | async\"\r\n [currentLanguageCode]=\"contentLanguage$ | async\"\r\n (languageCodeChange)=\"setLanguage($event)\"\r\n ></vdr-language-selector>\r\n </div>\r\n </vdr-ab-left>\r\n <vdr-ab-right>\r\n <vdr-action-bar-items locationId=\"product-list\"></vdr-action-bar-items>\r\n <a\r\n class=\"btn btn-primary\"\r\n [routerLink]=\"['./create']\"\r\n *vdrIfPermissions=\"['CreateCatalog', 'CreateProduct']\"\r\n >\r\n <clr-icon shape=\"plus\"></clr-icon>\r\n {{ 'catalog.create-new-product' | translate }}\r\n </a>\r\n </vdr-ab-right>\r\n</vdr-action-bar>\r\n\r\n<vdr-data-table\r\n [items]=\"items$ | async\"\r\n [itemsPerPage]=\"itemsPerPage$ | async\"\r\n [totalItems]=\"totalItems$ | async\"\r\n [currentPage]=\"currentPage$ | async\"\r\n (pageChange)=\"setPageNumber($event)\"\r\n (itemsPerPageChange)=\"setItemsPerPage($event)\"\r\n [selectionManager]=\"selectionManager\"\r\n>\r\n <vdr-bulk-action-menu\r\n locationId=\"product-list\"\r\n [hostComponent]=\"this\"\r\n [selectionManager]=\"selectionManager\"\r\n ></vdr-bulk-action-menu>\r\n <vdr-dt-column> </vdr-dt-column>\r\n <vdr-dt-column></vdr-dt-column>\r\n <vdr-dt-column></vdr-dt-column>\r\n <vdr-dt-column></vdr-dt-column>\r\n <ng-template let-result=\"item\">\r\n <td class=\"left align-middle image-col\" [class.disabled]=\"!result.enabled\">\r\n <div class=\"image-placeholder\">\r\n <img\r\n *ngIf=\"\r\n groupByProduct\r\n ? result.productAsset\r\n : result.productVariantAsset || result.productAsset as asset;\r\n else imagePlaceholder\r\n \"\r\n [src]=\"asset | assetPreview: 'tiny'\"\r\n />\r\n <ng-template #imagePlaceholder>\r\n <div class=\"placeholder\">\r\n <clr-icon shape=\"image\" size=\"48\"></clr-icon>\r\n </div>\r\n </ng-template>\r\n </div>\r\n </td>\r\n <td class=\"left align-middle\" [class.disabled]=\"!result.enabled\">\r\n <div>{{ groupByProduct ? result.productName : result.productVariantName }}</div>\r\n <div *ngIf=\"!groupByProduct\" class=\"sku\">{{ result.sku }}</div>\r\n </td>\r\n <td class=\"align-middle\" [class.disabled]=\"!result.enabled\">\r\n <vdr-chip *ngIf=\"!result.enabled\">{{ 'common.disabled' | translate }}</vdr-chip>\r\n </td>\r\n <td class=\"right align-middle\" [class.disabled]=\"!result.enabled\">\r\n <vdr-table-row-action\r\n class=\"edit-button\"\r\n iconShape=\"edit\"\r\n [label]=\"'common.edit' | translate\"\r\n [linkTo]=\"['./', result.productId]\"\r\n ></vdr-table-row-action>\r\n <vdr-dropdown>\r\n <button type=\"button\" class=\"btn btn-link btn-sm\" vdrDropdownTrigger>\r\n {{ 'common.actions' | translate }}\r\n <clr-icon shape=\"caret down\"></clr-icon>\r\n </button>\r\n <vdr-dropdown-menu vdrPosition=\"bottom-right\">\r\n <button\r\n type=\"button\"\r\n class=\"delete-button\"\r\n (click)=\"deleteProduct(result.productId)\"\r\n [disabled]=\"!(['DeleteCatalog', 'DeleteProduct'] | hasPermission)\"\r\n vdrDropdownItem\r\n >\r\n <clr-icon shape=\"trash\" class=\"is-danger\"></clr-icon>\r\n {{ 'common.delete' | translate }}\r\n </button>\r\n </vdr-dropdown-menu>\r\n </vdr-dropdown>\r\n </td>\r\n </ng-template>\r\n</vdr-data-table>\r\n","import { AfterViewInit, Component, OnInit, ViewChild } from '@angular/core';\r\nimport { ActivatedRoute, Router } from '@angular/router';\r\nimport { marker as _ } from '@biesbjerg/ngx-translate-extract-marker';\r\nimport {\r\n BaseListComponent,\r\n DataService,\r\n ItemOf,\r\n JobQueueService,\r\n JobState,\r\n LanguageCode,\r\n LogicalOperator,\r\n ModalService,\r\n NotificationService,\r\n ProductSearchInputComponent,\r\n SearchInput,\r\n SearchProductsQuery,\r\n SearchProductsQueryVariables,\r\n SelectionManager,\r\n ServerConfigService,\r\n} from '@vendure/admin-ui/core';\r\nimport { EMPTY, Observable } from 'rxjs';\r\nimport { delay, map, switchMap, take, takeUntil, tap, withLatestFrom } from 'rxjs/operators';\r\n\r\nexport type SearchItem = ItemOf<SearchProductsQuery, 'search'>;\r\n\r\n@Component({\r\n selector: 'vdr-products-list',\r\n templateUrl: './product-list.component.html',\r\n styleUrls: ['./product-list.component.scss'],\r\n})\r\nexport class ProductListComponent\r\n extends BaseListComponent<\r\n SearchProductsQuery,\r\n SearchItem,\r\n SearchProductsQueryVariables\r\n >\r\n implements OnInit, AfterViewInit\r\n{\r\n searchTerm = '';\r\n facetValueIds: string[] = [];\r\n groupByProduct = true;\r\n selectedFacetValueIds$: Observable<string[]>;\r\n facetValues$: Observable<SearchProductsQuery['search']['facetValues']>;\r\n availableLanguages$: Observable<LanguageCode[]>;\r\n contentLanguage$: Observable<LanguageCode>;\r\n pendingSearchIndexUpdates = 0;\r\n selectionManager: SelectionManager<SearchItem>;\r\n\r\n @ViewChild('productSearchInputComponent', { static: true })\r\n private productSearchInput: ProductSearchInputComponent;\r\n\r\n constructor(\r\n private dataService: DataService,\r\n private modalService: ModalService,\r\n private notificationService: NotificationService,\r\n private jobQueueService: JobQueueService,\r\n private serverConfigService: ServerConfigService,\r\n router: Router,\r\n route: ActivatedRoute,\r\n ) {\r\n super(router, route);\r\n this.route.queryParamMap\r\n .pipe(\r\n map(qpm => qpm.get('q')),\r\n takeUntil(this.destroy$),\r\n )\r\n .subscribe(term => {\r\n this.searchTerm = term || '';\r\n if (this.productSearchInput) {\r\n this.productSearchInput.setSearchTerm(term);\r\n }\r\n });\r\n this.selectedFacetValueIds$ = this.route.queryParamMap.pipe(map(qpm => qpm.getAll('fvids')));\r\n\r\n this.selectedFacetValueIds$.pipe(takeUntil(this.destroy$)).subscribe(ids => {\r\n this.facetValueIds = ids;\r\n if (this.productSearchInput) {\r\n this.productSearchInput.setFacetValues(ids);\r\n }\r\n });\r\n super.setQueryFn(\r\n (...args: any[]) =>\r\n this.dataService.product.searchProducts(this.searchTerm, ...args).refetchOnChannelChange(),\r\n data => data.search,\r\n // tslint:disable-next-line:no-shadowed-variable\r\n (skip, take) => ({\r\n input: {\r\n skip,\r\n take,\r\n term: this.searchTerm,\r\n facetValueIds: this.facetValueIds,\r\n facetValueOperator: LogicalOperator.AND,\r\n groupByProduct: this.groupByProduct,\r\n } as SearchInput,\r\n }),\r\n );\r\n this.selectionManager = new SelectionManager({\r\n multiSelect: true,\r\n itemsAreEqual: (a, b) =>\r\n this.groupByProduct ? a.productId === b.productId : a.productVariantId === b.productVariantId,\r\n additiveMode: true,\r\n });\r\n }\r\n\r\n ngOnInit() {\r\n super.ngOnInit();\r\n\r\n this.facetValues$ = this.result$.pipe(map(data => data.search.facetValues));\r\n\r\n this.facetValues$\r\n .pipe(take(1), delay(100), withLatestFrom(this.selectedFacetValueIds$))\r\n .subscribe(([__, ids]) => {\r\n this.productSearchInput.setFacetValues(ids);\r\n });\r\n this.availableLanguages$ = this.serverConfigService.getAvailableLanguages();\r\n this.contentLanguage$ = this.dataService.client\r\n .uiState()\r\n .mapStream(({ uiState }) => uiState.contentLanguage)\r\n .pipe(tap(() => this.refresh()));\r\n\r\n this.dataService.product\r\n .getPendingSearchIndexUpdates()\r\n .mapSingle(({ pendingSearchIndexUpdates }) => pendingSearchIndexUpdates)\r\n .subscribe(value => (this.pendingSearchIndexUpdates = value));\r\n }\r\n\r\n ngAfterViewInit() {\r\n if (this.productSearchInput && this.searchTerm) {\r\n setTimeout(() => this.productSearchInput.setSearchTerm(this.searchTerm));\r\n }\r\n }\r\n\r\n setSearchTerm(term: string) {\r\n this.searchTerm = term;\r\n this.setQueryParam({ q: term || null, page: 1 });\r\n this.refresh();\r\n }\r\n\r\n setFacetValueIds(ids: string[]) {\r\n this.facetValueIds = ids;\r\n this.setQueryParam({ fvids: ids, page: 1 });\r\n this.refresh();\r\n }\r\n\r\n rebuildSearchIndex() {\r\n this.dataService.product.reindex().subscribe(({ reindex }) => {\r\n this.notificationService.info(_('catalog.reindexing'));\r\n this.jobQueueService.addJob(reindex.id, job => {\r\n if (job.state === JobState.COMPLETED) {\r\n const time = new Intl.NumberFormat().format(job.duration || 0);\r\n this.notificationService.success(_('catalog.reindex-successful'), {\r\n count: job.result.indexedItemCount,\r\n time,\r\n });\r\n this.refresh();\r\n } else {\r\n this.notificationService.error(_('catalog.reindex-error'));\r\n }\r\n });\r\n });\r\n }\r\n\r\n runPendingSearchIndexUpdates() {\r\n this.dataService.product.runPendingSearchIndexUpdates().subscribe(value => {\r\n this.notificationService.info(_('catalog.running-search-index-updates'), {\r\n count: this.pendingSearchIndexUpdates,\r\n });\r\n this.pendingSearchIndexUpdates = 0;\r\n });\r\n }\r\n\r\n deleteProduct(productId: string) {\r\n this.modalService\r\n .dialog({\r\n title: _('catalog.confirm-delete-product'),\r\n buttons: [\r\n { type: 'secondary', label: _('common.cancel') },\r\n { type: 'danger', label: _('common.delete'), returnValue: true },\r\n ],\r\n })\r\n .pipe(\r\n switchMap(response => (response ? this.dataService.product.deleteProduct(productId) : EMPTY)),\r\n // Short delay to allow the product to be removed from the search index before\r\n // refreshing.\r\n delay(500),\r\n )\r\n .subscribe(\r\n () => {\r\n this.notificationService.success(_('common.notify-delete-success'), {\r\n entity: 'Product',\r\n });\r\n this.refresh();\r\n },\r\n err => {\r\n this.notificationService.error(_('common.notify-delete-error'), {\r\n entity: 'Product',\r\n });\r\n },\r\n );\r\n }\r\n\r\n setLanguage(code: LanguageCode) {\r\n this.dataService.client.setContentLanguage(code).subscribe();\r\n }\r\n}\r\n","<vdr-action-bar>\r\n <vdr-ab-left>\r\n <vdr-language-selector\r\n [availableLanguageCodes]=\"availableLanguages$ | async\"\r\n [currentLanguageCode]=\"languageCode$ | async\"\r\n (languageCodeChange)=\"setLanguage($event)\"\r\n ></vdr-language-selector>\r\n </vdr-ab-left>\r\n\r\n <vdr-ab-right>\r\n <div class=\"flex center\">\r\n <div class=\"mr2\">\r\n <clr-checkbox-wrapper>\r\n <input\r\n clrCheckbox\r\n type=\"checkbox\"\r\n id=\"auto-update\"\r\n [(ngModel)]=\"autoUpdateVariantNames\"\r\n />\r\n <label>{{ 'catalog.auto-update-product-variant-name' | translate }}</label>\r\n </clr-checkbox-wrapper>\r\n </div>\r\n <button\r\n *vdrIfPermissions=\"updatePermission\"\r\n class=\"btn btn-primary\"\r\n (click)=\"save()\"\r\n [disabled]=\"detailForm.pristine || detailForm.invalid\"\r\n >\r\n {{ 'common.update' | translate }}\r\n </button>\r\n </div>\r\n </vdr-ab-right>\r\n</vdr-action-bar>\r\n<form class=\"form\" [formGroup]=\"detailForm\" *ngIf=\"optionGroups$ | async as optionGroups\">\r\n <div formGroupName=\"optionGroups\" class=\"clr-row\">\r\n <div class=\"clr-col-12 clr-col-xl-6\" *ngFor=\"let optionGroup of getOptionGroups(); index as i\">\r\n <section class=\"card\" [formArrayName]=\"i\">\r\n <div class=\"card-header option-group-header\">\r\n <vdr-entity-info [entity]=\"optionGroup.value\"></vdr-entity-info>\r\n <div class=\"ml2\">{{ optionGroup.value.code }}</div>\r\n </div>\r\n <div class=\"card-block\">\r\n <vdr-form-field [label]=\"'common.name' | translate\" for=\"name\">\r\n <input\r\n [id]=\"'name-' + i\"\r\n type=\"text\"\r\n formControlName=\"name\"\r\n [readonly]=\"!(updatePermission | hasPermission)\"\r\n />\r\n </vdr-form-field>\r\n <vdr-form-field [label]=\"'common.code' | translate\" for=\"code\">\r\n <input\r\n [id]=\"'code-' + i\"\r\n type=\"text\"\r\n [readonly]=\"!(updatePermission | hasPermission)\"\r\n formControlName=\"code\"\r\n />\r\n </vdr-form-field>\r\n </div>\r\n <section class=\"card-block\">\r\n <table class=\"facet-values-list table mt2 mb4\" formGroupName=\"options\">\r\n <thead>\r\n <tr>\r\n <th></th>\r\n <th>{{ 'common.name' | translate }}</th>\r\n <th>{{ 'common.code' | translate }}</th>\r\n </tr>\r\n </thead>\r\n <tbody>\r\n <tr\r\n class=\"facet-value\"\r\n *ngFor=\"let option of getOptions(optionGroup); let i = index\"\r\n [formGroupName]=\"i\"\r\n >\r\n <td class=\"align-middle\">\r\n <vdr-entity-info [entity]=\"option.value\"></vdr-entity-info>\r\n </td>\r\n <td class=\"align-middle\">\r\n <input\r\n type=\"text\"\r\n formControlName=\"name\"\r\n [readonly]=\"!(updatePermission | hasPermission)\"\r\n />\r\n </td>\r\n <td class=\"align-middle\"><input type=\"text\" formControlName=\"code\" /></td>\r\n </tr>\r\n </tbody>\r\n </table>\r\n </section>\r\n </section>\r\n </div>\r\n </div>\r\n</form>\r\n","import { ChangeDetectionStrategy, ChangeDetectorRef, Component, OnInit } from '@angular/core';\r\nimport { FormArray, FormBuilder, FormGroup } from '@angular/forms';\r\nimport { ActivatedRoute, Router } from '@angular/router';\r\nimport { marker as _ } from '@biesbjerg/ngx-translate-extract-marker';\r\nimport {\r\n BaseDetailComponent,\r\n createUpdatedTranslatable,\r\n CustomFieldConfig,\r\n DataService,\r\n findTranslation,\r\n GetProductVariantOptionsQuery,\r\n LanguageCode,\r\n NotificationService,\r\n Permission,\r\n ProductOptionFragment,\r\n ProductOptionGroup,\r\n ProductOptionGroupFragment,\r\n ServerConfigService,\r\n UpdateProductOptionGroupInput,\r\n UpdateProductOptionInput,\r\n} from '@vendure/admin-ui/core';\r\nimport { combineLatest, forkJoin, Observable } from 'rxjs';\r\nimport { map, mergeMap, take } from 'rxjs/operators';\r\n\r\nimport { ProductDetailService } from '../../providers/product-detail/product-detail.service';\r\n\r\ntype ProductWithOptions = NonNullable<GetProductVariantOptionsQuery['product']>;\r\n\r\n@Component({\r\n selector: 'vdr-product-options-editor',\r\n templateUrl: './product-options-editor.component.html',\r\n styleUrls: ['./product-options-editor.component.scss'],\r\n changeDetection: ChangeDetectionStrategy.OnPush,\r\n})\r\nexport class ProductOptionsEditorComponent extends BaseDetailComponent<ProductWithOptions> implements OnInit {\r\n detailForm: FormGroup;\r\n optionGroups$: Observable<ProductWithOptions['optionGroups']>;\r\n languageCode$: Observable<LanguageCode>;\r\n availableLanguages$: Observable<LanguageCode[]>;\r\n optionGroupCustomFields: CustomFieldConfig[];\r\n optionCustomFields: CustomFieldConfig[];\r\n autoUpdateVariantNames = true;\r\n readonly updatePermission = [Permission.UpdateCatalog, Permission.UpdateProduct];\r\n\r\n constructor(\r\n protected route: ActivatedRoute,\r\n protected router: Router,\r\n protected serverConfigService: ServerConfigService,\r\n protected dataService: DataService,\r\n private productDetailService: ProductDetailService,\r\n private formBuilder: FormBuilder,\r\n private changeDetector: ChangeDetectorRef,\r\n private notificationService: NotificationService,\r\n ) {\r\n super(route, router, serverConfigService, dataService);\r\n this.optionGroupCustomFields = this.getCustomFieldConfig('ProductOptionGroup');\r\n this.optionCustomFields = this.getCustomFieldConfig('ProductOption');\r\n }\r\n\r\n ngOnInit(): void {\r\n this.optionGroups$ = this.route.snapshot.data.entity.pipe(\r\n map((product: ProductWithOptions) => product.optionGroups),\r\n );\r\n this.detailForm = new FormGroup({\r\n optionGroups: new FormArray([]),\r\n });\r\n super.init();\r\n }\r\n\r\n getOptionGroups(): FormGroup[] {\r\n const optionGroups = this.detailForm.get('optionGroups');\r\n return (optionGroups as FormArray).controls as FormGroup[];\r\n }\r\n\r\n getOptions(optionGroup: FormGroup): FormGroup[] {\r\n const options = optionGroup.get('options');\r\n return (options as FormArray).controls as FormGroup[];\r\n }\r\n\r\n save() {\r\n if (this.detailForm.invalid || this.detailForm.pristine) {\r\n return;\r\n }\r\n // tslint:disable-next-line:no-non-null-assertion\r\n const $product = this.dataService.product.getProduct(this.id).mapSingle(data => data.product!);\r\n combineLatest(this.entity$, this.languageCode$, $product)\r\n .pipe(\r\n take(1),\r\n mergeMap(([{ optionGroups }, languageCode, product]) => {\r\n const updateOperations: Array<Observable<any>> = [];\r\n for (const optionGroupForm of this.getOptionGroups()) {\r\n if (optionGroupForm.get('name')?.dirty || optionGroupForm.get('code')?.dirty) {\r\n const optionGroupEntity = optionGroups.find(\r\n og => og.id === optionGroupForm.value.id,\r\n );\r\n if (optionGroupEntity) {\r\n const input = this.getUpdatedOptionGroup(\r\n optionGroupEntity,\r\n optionGroupForm,\r\n languageCode,\r\n );\r\n updateOperations.push(\r\n this.dataService.product.updateProductOptionGroup(input),\r\n );\r\n }\r\n }\r\n\r\n for (const optionForm of this.getOptions(optionGroupForm)) {\r\n if (optionForm.get('name')?.dirty || optionForm.get('code')?.dirty) {\r\n const optionGroup = optionGroups\r\n .find(og => og.id === optionGroupForm.value.id)\r\n ?.options.find(o => o.id === optionForm.value.id);\r\n if (optionGroup) {\r\n const input = this.getUpdatedOption(\r\n optionGroup,\r\n optionForm,\r\n languageCode,\r\n );\r\n updateOperations.push(\r\n this.productDetailService.updateProductOption(\r\n { ...input, autoUpdate: this.autoUpdateVariantNames },\r\n product,\r\n languageCode,\r\n ),\r\n );\r\n }\r\n }\r\n }\r\n }\r\n return forkJoin(updateOperations);\r\n }),\r\n )\r\n .subscribe(\r\n () => {\r\n this.detailForm.markAsPristine();\r\n this.changeDetector.markForCheck();\r\n this.notificationService.success(_('common.notify-update-success'), {\r\n entity: 'ProductOptionGroup',\r\n });\r\n },\r\n err => {\r\n this.notificationService.error(_('common.notify-update-error'), {\r\n entity: 'ProductOptionGroup',\r\n });\r\n },\r\n );\r\n }\r\n\r\n private getUpdatedOptionGroup(\r\n optionGroup: ProductOptionGroupFragment,\r\n optionGroupFormGroup: FormGroup,\r\n languageCode: LanguageCode,\r\n ): UpdateProductOptionGroupInput {\r\n const input = createUpdatedTranslatable({\r\n translatable: optionGroup,\r\n updatedFields: optionGroupFormGroup.value,\r\n customFieldConfig: this.optionGroupCustomFields,\r\n languageCode,\r\n defaultTranslation: {\r\n languageCode,\r\n name: optionGroup.name || '',\r\n },\r\n });\r\n return input;\r\n }\r\n\r\n private getUpdatedOption(\r\n option: ProductOptionFragment,\r\n optionFormGroup: FormGroup,\r\n languageCode: LanguageCode,\r\n ): UpdateProductOptionInput {\r\n const input = createUpdatedTranslatable({\r\n translatable: option,\r\n updatedFields: optionFormGroup.value,\r\n customFieldConfig: this.optionGroupCustomFields,\r\n languageCode,\r\n defaultTranslation: {\r\n languageCode,\r\n name: option.name || '',\r\n },\r\n });\r\n return input;\r\n }\r\n\r\n protected setFormValues(entity: ProductWithOptions, languageCode: LanguageCode): void {\r\n const groupsFormArray = new FormArray([]);\r\n for (const optionGroup of entity.optionGroups) {\r\n const groupTranslation = findTranslation(optionGroup, languageCode);\r\n const group = {\r\n id: optionGroup.id,\r\n createdAt: optionGroup.createdAt,\r\n updatedAt: optionGroup.updatedAt,\r\n code: optionGroup.code,\r\n name: groupTranslation ? groupTranslation.name : '',\r\n };\r\n const optionsFormArray = new FormArray([]);\r\n\r\n for (const option of optionGroup.options) {\r\n const optionTranslation = findTranslation(option, languageCode);\r\n const optionControl = this.formBuilder.group({\r\n id: option.id,\r\n createdAt: option.createdAt,\r\n updatedAt: option.updatedAt,\r\n code: option.code,\r\n name: optionTranslation ? optionTranslation.name : '',\r\n });\r\n optionsFormArray.push(optionControl);\r\n }\r\n\r\n const groupControl = this.formBuilder.group(group);\r\n groupControl.addControl('options', optionsFormArray);\r\n groupsFormArray.push(groupControl);\r\n }\r\n this.detailForm.setControl('optionGroups', groupsFormArray);\r\n }\r\n}\r\n","<ng-template vdrDialogTitle>\r\n {{ 'catalog.confirm-deletion-of-unused-variants-title' | translate }}\r\n</ng-template>\r\n{{ 'catalog.confirm-deletion-of-unused-variants-body' | translate }}\r\n<ul>\r\n <li *ngFor=\"let variant of variants\">{{ variant.name }} ({{ variant.sku }})</li>\r\n</ul>\r\n<ng-template vdrDialogButtons>\r\n <button type=\"button\" class=\"btn\" (click)=\"cancel()\">{{ 'common.cancel' | translate }}</button>\r\n <button type=\"submit\" (click)=\"confirm()\" class=\"btn btn-primary\">\r\n {{ 'common.confirm' | translate }}\r\n </button>\r\n</ng-template>\r\n","import { ChangeDetectionStrategy, Component } from '@angular/core';\r\nimport { Dialog, GetProductVariantOptionsQuery } from '@vendure/admin-ui/core';\r\n\r\n@Component({\r\n selector: 'vdr-confirm-variant-deletion-dialog',\r\n templateUrl: './confirm-variant-deletion-dialog.component.html',\r\n styleUrls: ['./confirm-variant-deletion-dialog.component.scss'],\r\n changeDetection: ChangeDetectionStrategy.OnPush,\r\n})\r\nexport class ConfirmVariantDeletionDialogComponent implements Dialog<boolean> {\r\n resolveWith: (result?: boolean) => void;\r\n variants: NonNullable<GetProductVariantOptionsQuery['product']>['variants'] = [];\r\n\r\n confirm() {\r\n this.resolveWith(true);\r\n }\r\n\r\n cancel() {\r\n this.resolveWith();\r\n }\r\n}\r\n","<vdr-action-bar>\r\n <vdr-ab-right>\r\n <button\r\n class=\"btn btn-primary\"\r\n (click)=\"save()\"\r\n [disabled]=\"(!formValueChanged && !optionsChanged) || getVariantsToAdd().length === 0\"\r\n >\r\n {{ 'common.add-new-variants' | translate: { count: getVariantsToAdd().length } }}\r\n </button>\r\n </vdr-ab-right>\r\n</vdr-action-bar>\r\n\r\n<div *ngFor=\"let group of optionGroups; index as i\" class=\"option-groups\">\r\n <div class=\"name\">\r\n <label>{{ 'catalog.option' | translate }}</label>\r\n <input clrInput [(ngModel)]=\"group.name\" name=\"name\" [readonly]=\"!group.isNew\" />\r\n </div>\r\n <div class=\"values\">\r\n <label>{{ 'catalog.option-values' | translate }}</label>\r\n <vdr-option-value-input\r\n #optionValueInputComponent\r\n [options]=\"group.values\"\r\n [groupName]=\"group.name\"\r\n [disabled]=\"group.name === ''\"\r\n (add)=\"addOption(i, $event.name)\"\r\n (remove)=\"removeOption(i, $event)\"\r\n ></vdr-option-value-input>\r\n </div>\r\n <div>\r\n <button\r\n [disabled]=\"group.locked\"\r\n class=\"btn btn-icon btn-danger-outline mt5\" (click)=\"removeOptionGroup(group)\">\r\n <clr-icon shape=\"trash\"></clr-icon>\r\n </button>\r\n </div>\r\n</div>\r\n<button class=\"btn btn-primary-outline btn-sm\" (click)=\"addOptionGroup()\">\r\n <clr-icon shape=\"plus\"></clr-icon>\r\n {{ 'catalog.add-option' | translate }}\r\n</button>\r\n\r\n<div class=\"variants-preview\">\r\n <table class=\"table\">\r\n <thead>\r\n <tr>\r\n <th></th>\r\n <th>{{ 'catalog.variant' | translate }}</th>\r\n <th>{{ 'catalog.sku' | translate }}</th>\r\n <th>{{ 'catalog.price' | translate }}</th>\r\n <th>{{ 'catalog.stock-on-hand' | translate }}</th>\r\n <th></th>\r\n </tr>\r\n </thead>\r\n <tr *ngFor=\"let variant of generatedVariants\" [class.disabled]=\"!variant.enabled || variant.existing\">\r\n <td class=\"left\">\r\n <clr-checkbox-wrapper *ngIf=\"!variant.existing\">\r\n <input\r\n type=\"checkbox\"\r\n [(ngModel)]=\"variant.enabled\"\r\n name=\"enabled\"\r\n clrCheckbox\r\n (ngModelChange)=\"formValueChanged = true\"\r\n />\r\n <label>{{ 'common.create' | translate }}</label>\r\n </clr-checkbox-wrapper>\r\n </td>\r\n <td>\r\n {{ getVariantName(variant) | translate }}\r\n </td>\r\n <td>\r\n <div class=\"flex center\">\r\n <clr-input-container *ngIf=\"!variant.existing\">\r\n <input\r\n clrInput\r\n type=\"text\"\r\n [(ngModel)]=\"variant.sku\"\r\n [placeholder]=\"'catalog.sku' | translate\"\r\n name=\"sku\"\r\n required\r\n (ngModelChange)=\"onFormChanged(variant)\"\r\n />\r\n </clr-input-container>\r\n <span *ngIf=\"variant.existing\">{{ variant.sku }}</span>\r\n </div>\r\n </td>\r\n <td>\r\n <div class=\"flex center\">\r\n <clr-input-container *ngIf=\"!variant.existing\">\r\n <vdr-currency-input\r\n clrInput\r\n [(ngModel)]=\"variant.price\"\r\n name=\"price\"\r\n [currencyCode]=\"currencyCode\"\r\n (ngModelChange)=\"onFormChanged(variant)\"\r\n ></vdr-currency-input>\r\n </clr-input-container>\r\n <span *ngIf=\"variant.existing\">{{ variant.price | localeCurrency: currencyCode }}</span>\r\n </div>\r\n </td>\r\n <td>\r\n <div class=\"flex center\">\r\n <clr-input-container *ngIf=\"!variant.existing\">\r\n <input\r\n clrInput\r\n type=\"number\"\r\n [(ngModel)]=\"variant.stock\"\r\n name=\"stock\"\r\n min=\"0\"\r\n step=\"1\"\r\n (ngModelChange)=\"onFormChanged(variant)\"\r\n />\r\n </clr-input-container>\r\n <span *ngIf=\"variant.existing\">{{ variant.stock }}</span>\r\n </div>\r\n </td>\r\n <td>\r\n <vdr-dropdown *ngIf=\"variant.productVariantId as productVariantId\">\r\n <button class=\"icon-button\" vdrDropdownTrigger>\r\n <clr-icon shape=\"ellipsis-vertical\"></clr-icon>\r\n </button>\r\n <vdr-dropdown-menu vdrPosition=\"bottom-right\">\r\n <button\r\n type=\"button\"\r\n class=\"delete-button\"\r\n (click)=\"deleteVariant(productVariantId, variant.options)\"\r\n vdrDropdownItem\r\n >\r\n <clr-icon shape=\"trash\" class=\"is-danger\"></clr-icon>\r\n {{ 'common.delete' | translate }}\r\n </button>\r\n </vdr-dropdown-menu>\r\n </vdr-dropdown>\r\n </td>\r\n </tr>\r\n </table>\r\n</div>\r\n","import { ChangeDetectionStrategy, Component, OnInit } from '@angular/core';\r\nimport { ActivatedRoute } from '@angular/router';\r\nimport { marker as _ } from '@biesbjerg/ngx-translate-extract-marker';\r\nimport {\r\n CreateProductOptionGroupMutation,\r\n CreateProductOptionInput,\r\n CurrencyCode,\r\n DataService,\r\n DeactivateAware,\r\n DeletionResult,\r\n getDefaultUiLanguage,\r\n GetProductVariantOptionsQuery,\r\n LanguageCode,\r\n ModalService,\r\n NotificationService,\r\n ProductOptionGroupWithOptionsFragment,\r\n} from '@vendure/admin-ui/core';\r\nimport { normalizeString } from '@vendure/common/lib/normalize-string';\r\nimport { pick } from '@vendure/common/lib/pick';\r\nimport { generateAllCombinations, notNullOrUndefined } from '@vendure/common/lib/shared-utils';\r\nimport { unique } from '@vendure/common/lib/unique';\r\nimport { EMPTY, forkJoin, Observable, of } from 'rxjs';\r\nimport { defaultIfEmpty, filter, map, mergeMap, switchMap } from 'rxjs/operators';\r\n\r\nimport { ProductDetailService } from '../../providers/product-detail/product-detail.service';\r\nimport { ConfirmVariantDeletionDialogComponent } from '../confirm-variant-deletion-dialog/confirm-variant-deletion-dialog.component';\r\n\r\nexport class GeneratedVariant {\r\n isDefault: boolean;\r\n options: Array<{ name: string; id?: string }>;\r\n productVariantId?: string;\r\n enabled: boolean;\r\n existing: boolean;\r\n sku: string;\r\n price: number;\r\n stock: number;\r\n\r\n constructor(config: Partial<GeneratedVariant>) {\r\n for (const key of Object.keys(config)) {\r\n this[key] = config[key];\r\n }\r\n }\r\n}\r\n\r\ninterface OptionGroupUiModel {\r\n id?: string;\r\n isNew: boolean;\r\n name: string;\r\n locked: boolean;\r\n values: Array<{\r\n id?: string;\r\n name: string;\r\n locked: boolean;\r\n }>;\r\n}\r\n\r\n@Component({\r\n selector: 'vdr-product-variants-editor',\r\n templateUrl: './product-variants-editor.component.html',\r\n styleUrls: ['./product-variants-editor.component.scss'],\r\n changeDetection: ChangeDetectionStrategy.Default,\r\n})\r\nexport class ProductVariantsEditorComponent implements OnInit, DeactivateAware {\r\n formValueChanged = false;\r\n optionsChanged = false;\r\n generatedVariants: GeneratedVariant[] = [];\r\n optionGroups: OptionGroupUiModel[];\r\n product: NonNullable<GetProductVariantOptionsQuery['product']>;\r\n currencyCode: CurrencyCode;\r\n private languageCode: LanguageCode;\r\n\r\n constructor(\r\n private route: ActivatedRoute,\r\n private dataService: DataService,\r\n private productDetailService: ProductDetailService,\r\n private notificationService: NotificationService,\r\n private modalService: ModalService,\r\n ) {}\r\n\r\n ngOnInit() {\r\n this.initOptionsAndVariants();\r\n this.languageCode =\r\n (this.route.snapshot.paramMap.get('lang') as LanguageCode) || getDefaultUiLanguage();\r\n this.dataService.settings.getActiveChannel().single$.subscribe(data => {\r\n this.currencyCode = data.activeChannel.currencyCode;\r\n });\r\n }\r\n\r\n onFormChanged(variantInfo: GeneratedVariant) {\r\n this.formValueChanged = true;\r\n variantInfo.enabled = true;\r\n }\r\n\r\n canDeactivate(): boolean {\r\n return !this.formValueChanged;\r\n }\r\n\r\n getVariantsToAdd() {\r\n return this.generatedVariants.filter(v => !v.existing && v.enabled);\r\n }\r\n\r\n getVariantName(variant: GeneratedVariant) {\r\n return variant.options.length === 0\r\n ? _('catalog.default-variant')\r\n : variant.options.map(o => o.name).join(' ');\r\n }\r\n\r\n addOptionGroup() {\r\n this.optionGroups.push({\r\n isNew: true,\r\n locked: false,\r\n name: '',\r\n values: [],\r\n });\r\n this.optionsChanged = true;\r\n }\r\n\r\n removeOptionGroup(optionGroup: OptionGroupUiModel) {\r\n const id = optionGroup.id;\r\n if (optionGroup.isNew) {\r\n this.optionGroups = this.optionGroups.filter(og => og !== optionGroup);\r\n this.generateVariants();\r\n this.optionsChanged = true;\r\n } else if (id) {\r\n this.modalService\r\n .dialog({\r\n title: _('catalog.confirm-delete-product-option-group'),\r\n translationVars: { name: optionGroup.name },\r\n buttons: [\r\n { type: 'secondary', label: _('common.cancel') },\r\n { type: 'danger', label: _('common.delete'), returnValue: true },\r\n ],\r\n })\r\n .pipe(\r\n switchMap(val => {\r\n if (val) {\r\n return this.dataService.product.removeOptionGroupFromProduct({\r\n optionGroupId: id,\r\n productId: this.product.id,\r\n });\r\n } else {\r\n return EMPTY;\r\n }\r\n }),\r\n )\r\n .subscribe(({ removeOptionGroupFromProduct }) => {\r\n if (removeOptionGroupFromProduct.__typename === 'Product') {\r\n this.notificationService.success(_('common.notify-delete-success'), {\r\n entity: 'ProductOptionGroup',\r\n });\r\n this.initOptionsAndVariants();\r\n this.optionsChanged = true;\r\n } else if (removeOptionGroupFromProduct.__typename === 'ProductOptionInUseError') {\r\n this.notificationService.error(removeOptionGroupFromProduct.message ?? '');\r\n }\r\n });\r\n }\r\n }\r\n\r\n addOption(index: number, optionName: string) {\r\n const group = this.optionGroups[index];\r\n if (group) {\r\n group.values.push({ name: optionName, locked: false });\r\n this.generateVariants();\r\n this.optionsChanged = true;\r\n }\r\n }\r\n\r\n removeOption(index: number, { id, name }: { id?: string; name: string }) {\r\n const optionGroup = this.optionGroups[index];\r\n if (optionGroup) {\r\n if (!id) {\r\n optionGroup.values = optionGroup.values.filter(v => v.name !== name);\r\n this.generateVariants();\r\n } else {\r\n this.modalService\r\n .dialog({\r\n title: _('catalog.confirm-delete-product-option'),\r\n translationVars: { name },\r\n buttons: [\r\n { type: 'secondary', label: _('common.cancel') },\r\n { type: 'danger', label: _('common.delete'), returnValue: true },\r\n ],\r\n })\r\n .pipe(\r\n switchMap(val => {\r\n if (val) {\r\n return this.dataService.product.deleteProductOption(id);\r\n } else {\r\n return EMPTY;\r\n }\r\n }),\r\n )\r\n .subscribe(({ deleteProductOption }) => {\r\n if (deleteProductOption.result === DeletionResult.DELETED) {\r\n this.notificationService.success(_('common.notify-delete-success'), {\r\n entity: 'ProductOption',\r\n });\r\n optionGroup.values = optionGroup.values.filter(v => v.id !== id);\r\n this.generateVariants();\r\n this.optionsChanged = true;\r\n } else {\r\n this.notificationService.error(deleteProductOption.message ?? '');\r\n }\r\n });\r\n }\r\n }\r\n }\r\n\r\n generateVariants() {\r\n const groups = this.optionGroups.map(g => g.values);\r\n const previousVariants = this.generatedVariants;\r\n const generatedVariantFactory = (\r\n isDefault: boolean,\r\n options: GeneratedVariant['options'],\r\n existingVariant?: NonNullable<GetProductVariantOptionsQuery['product']>['variants'][number],\r\n prototypeVariant?: NonNullable<GetProductVariantOptionsQuery['product']>['variants'][number],\r\n ): GeneratedVariant => {\r\n const prototype = this.getVariantPrototype(options, previousVariants);\r\n return new GeneratedVariant({\r\n enabled: true,\r\n existing: !!existingVariant,\r\n productVariantId: existingVariant?.id,\r\n isDefault,\r\n options,\r\n price: existingVariant?.price ?? prototypeVariant?.price ?? prototype.price,\r\n sku: existingVariant?.sku ?? prototypeVariant?.sku ?? prototype.sku,\r\n stock: existingVariant?.stockOnHand ?? prototypeVariant?.stockOnHand ?? prototype.stock,\r\n });\r\n };\r\n this.generatedVariants = groups.length\r\n ? generateAllCombinations(groups).map(options => {\r\n const existingVariant = this.product.variants.find(v =>\r\n this.optionsAreEqual(v.options, options),\r\n );\r\n const prototypeVariant = this.product.variants.find(v =>\r\n this.optionsAreSubset(v.options, options),\r\n );\r\n return generatedVariantFactory(false, options, existingVariant, prototypeVariant);\r\n })\r\n : [generatedVariantFactory(true, [], this.product.variants[0])];\r\n }\r\n\r\n /**\r\n * Returns one of the existing variants to base the newly-generated variant's\r\n * details off.\r\n */\r\n private getVariantPrototype(\r\n options: GeneratedVariant['options'],\r\n previousVariants: GeneratedVariant[],\r\n ): Pick<GeneratedVariant, 'sku' | 'price' | 'stock'> {\r\n const variantsWithSimilarOptions = previousVariants.filter(v =>\r\n options.map(o => o.name).filter(name => v.options.map(o => o.name).includes(name)),\r\n );\r\n if (variantsWithSimilarOptions.length) {\r\n return pick(previousVariants[0], ['sku', 'price', 'stock']);\r\n }\r\n return {\r\n sku: '',\r\n price: 0,\r\n stock: 0,\r\n };\r\n }\r\n\r\n deleteVariant(id: string, options: GeneratedVariant['options']) {\r\n this.modalService\r\n .dialog({\r\n title: _('catalog.confirm-delete-product-variant'),\r\n translationVars: { name: options.map(o => o.name).join(' ') },\r\n buttons: [\r\n { type: 'secondary', label: _('common.cancel') },\r\n { type: 'danger', label: _('common.delete'), returnValue: true },\r\n ],\r\n })\r\n .pipe(\r\n switchMap(response =>\r\n response ? this.productDetailService.deleteProductVariant(id, this.product.id) : EMPTY,\r\n ),\r\n switchMap(() => this.reFetchProduct(null)),\r\n )\r\n .subscribe(\r\n () => {\r\n this.notificationService.success(_('common.notify-delete-success'), {\r\n entity: 'ProductVariant',\r\n });\r\n this.initOptionsAndVariants();\r\n },\r\n err => {\r\n this.notificationService.error(_('common.notify-delete-error'), {\r\n entity: 'ProductVariant',\r\n });\r\n },\r\n );\r\n }\r\n\r\n save() {\r\n this.optionGroups = this.optionGroups.filter(g => g.values.length);\r\n const newOptionGroups = this.optionGroups\r\n .filter(og => og.isNew)\r\n .map(og => ({\r\n name: og.name,\r\n values: [],\r\n }));\r\n\r\n this.checkUniqueSkus()\r\n .pipe(\r\n mergeMap(() => this.confirmDeletionOfObsoleteVariants()),\r\n mergeMap(() =>\r\n this.productDetailService.createProductOptionGroups(newOptionGroups, this.languageCode),\r\n ),\r\n mergeMap(createdOptionGroups => this.addOptionGroupsToProduct(createdOptionGroups)),\r\n mergeMap(createdOptionGroups => this.addNewOptionsToGroups(createdOptionGroups)),\r\n mergeMap(groupsIds => this.fetchOptionGroups(groupsIds)),\r\n mergeMap(groups => this.createNewProductVariants(groups)),\r\n mergeMap(res => this.deleteObsoleteVariants(res.createProductVariants)),\r\n mergeMap(variants => this.reFetchProduct(variants)),\r\n )\r\n .subscribe({\r\n next: variants => {\r\n this.formValueChanged = false;\r\n this.notificationService.success(_('catalog.created-new-variants-success'), {\r\n count: variants.length,\r\n });\r\n this.initOptionsAndVariants();\r\n this.optionsChanged = false;\r\n },\r\n });\r\n }\r\n\r\n private checkUniqueSkus() {\r\n const withDuplicateSkus = this.generatedVariants.filter((variant, index) => {\r\n return (\r\n variant.enabled &&\r\n this.generatedVariants.find(gv => gv.sku.trim() === variant.sku.trim() && gv !== variant)\r\n );\r\n });\r\n if (withDuplicateSkus.length) {\r\n return this.modalService\r\n .dialog({\r\n title: _('catalog.duplicate-sku-warning'),\r\n body: unique(withDuplicateSkus.map(v => `${v.sku}`)).join(', '),\r\n buttons: [{ label: _('common.close'), returnValue: false, type: 'primary' }],\r\n })\r\n .pipe(mergeMap(res => EMPTY));\r\n } else {\r\n return of(true);\r\n }\r\n }\r\n\r\n private confirmDeletionOfObsoleteVariants(): Observable<boolean> {\r\n const obsoleteVariants = this.getObsoleteVariants();\r\n if (obsoleteVariants.length) {\r\n return this.modalService\r\n .fromComponent(ConfirmVariantDeletionDialogComponent, {\r\n locals: {\r\n variants: obsoleteVariants,\r\n },\r\n })\r\n .pipe(\r\n mergeMap(res => {\r\n return res === true ? of(true) : EMPTY;\r\n }),\r\n );\r\n } else {\r\n return of(true);\r\n }\r\n }\r\n\r\n private getObsoleteVariants() {\r\n return this.product.variants.filter(\r\n variant => !this.generatedVariants.find(gv => gv.productVariantId === variant.id),\r\n );\r\n }\r\n\r\n private hasOnlyDefaultVariant(product: NonNullable<GetProductVariantOptionsQuery['product']>): boolean {\r\n return product.variants.length === 1 && product.optionGroups.length === 0;\r\n }\r\n\r\n private addOptionGroupsToProduct(\r\n createdOptionGroups: Array<CreateProductOptionGroupMutation['createProductOptionGroup']>,\r\n ): Observable<Array<CreateProductOptionGroupMutation['createProductOptionGroup']>> {\r\n if (createdOptionGroups.length) {\r\n return forkJoin(\r\n createdOptionGroups.map(optionGroup => {\r\n return this.dataService.product.addOptionGroupToProduct({\r\n productId: this.product.id,\r\n optionGroupId: optionGroup.id,\r\n });\r\n }),\r\n ).pipe(map(() => createdOptionGroups));\r\n } else {\r\n return of([]);\r\n }\r\n }\r\n\r\n private addNewOptionsToGroups(\r\n createdOptionGroups: Array<CreateProductOptionGroupMutation['createProductOptionGroup']>,\r\n ): Observable<string[]> {\r\n const newOptions: CreateProductOptionInput[] = this.optionGroups\r\n .map(og => {\r\n const createdGroup = createdOptionGroups.find(cog => cog.name === og.name);\r\n const productOptionGroupId = createdGroup ? createdGroup.id : og.id;\r\n if (!productOptionGroupId) {\r\n throw new Error('Could not get a productOptionGroupId');\r\n }\r\n return og.values\r\n .filter(v => !v.locked)\r\n .map(v => ({\r\n productOptionGroupId,\r\n code: normalizeString(v.name, '-'),\r\n translations: [{ name: v.name, languageCode: this.languageCode }],\r\n }));\r\n })\r\n .reduce((flat, options) => [...flat, ...options], []);\r\n\r\n const allGroupIds = [\r\n ...createdOptionGroups.map(g => g.id),\r\n ...this.optionGroups.map(g => g.id).filter(notNullOrUndefined),\r\n ];\r\n\r\n if (newOptions.length) {\r\n return forkJoin(newOptions.map(input => this.dataService.product.addOptionToGroup(input))).pipe(\r\n map(() => allGroupIds),\r\n );\r\n } else {\r\n return of(allGroupIds);\r\n }\r\n }\r\n\r\n private fetchOptionGroups(groupsIds: string[]): Observable<ProductOptionGroupWithOptionsFragment[]> {\r\n return forkJoin(\r\n groupsIds.map(id =>\r\n this.dataService.product\r\n .getProductOptionGroup(id)\r\n .mapSingle(data => data.productOptionGroup)\r\n .pipe(filter(notNullOrUndefined)),\r\n ),\r\n ).pipe(defaultIfEmpty([] as ProductOptionGroupWithOptionsFragment[]));\r\n }\r\n\r\n private createNewProductVariants(groups: ProductOptionGroupWithOptionsFragment[]) {\r\n const options = groups\r\n .filter(notNullOrUndefined)\r\n .map(og => og.options)\r\n .reduce((flat, o) => [...flat, ...o], []);\r\n const variants = this.generatedVariants\r\n .filter(v => v.enabled && !v.existing)\r\n .map(v => {\r\n const optionIds = groups.map((group, index) => {\r\n const option = group.options.find(o => o.name === v.options[index].name);\r\n if (option) {\r\n return option.id;\r\n } else {\r\n throw new Error(`Could not find a matching option for group ${group.name}`);\r\n }\r\n });\r\n return {\r\n price: v.price,\r\n sku: v.sku,\r\n stock: v.stock,\r\n optionIds,\r\n };\r\n });\r\n return this.productDetailService.createProductVariants(\r\n this.product,\r\n variants,\r\n options,\r\n this.languageCode,\r\n );\r\n }\r\n\r\n private deleteObsoleteVariants<T>(input: T): Observable<T | T[]> {\r\n const obsoleteVariants = this.getObsoleteVariants();\r\n if (obsoleteVariants.length) {\r\n const deleteOperations = obsoleteVariants.map(v =>\r\n this.dataService.product.deleteProductVariant(v.id).pipe(map(() => input)),\r\n );\r\n return forkJoin(...deleteOperations);\r\n } else {\r\n return of(input);\r\n }\r\n }\r\n\r\n private reFetchProduct<T>(input: T): Observable<T> {\r\n // Re-fetch the Product to force an update to the view.\r\n const id = this.route.snapshot.paramMap.get('id');\r\n if (id) {\r\n return this.dataService.product.getProduct(id).single$.pipe(map(() => input));\r\n } else {\r\n return of(input);\r\n }\r\n }\r\n\r\n initOptionsAndVariants() {\r\n this.dataService.product\r\n // tslint:disable-next-line:no-non-null-assertion\r\n .getProductVariantsOptions(this.route.snapshot.paramMap.get('id')!)\r\n // tslint:disable-next-line:no-non-null-assertion\r\n .mapSingle(({ product }) => product!)\r\n .subscribe(p => {\r\n this.product = p;\r\n const allUsedOptionIds = p.variants.map(v => v.options.map(option => option.id)).flat();\r\n const allUsedOptionGroupIds = p.variants\r\n .map(v => v.options.map(option => option.groupId))\r\n .flat();\r\n this.optionGroups = p.optionGroups.map(og => {\r\n return {\r\n id: og.id,\r\n isNew: false,\r\n name: og.name,\r\n locked: allUsedOptionGroupIds.includes(og.id),\r\n values: og.options.map(o => ({\r\n id: o.id,\r\n name: o.name,\r\n locked: allUsedOptionIds.includes(o.id),\r\n })),\r\n };\r\n });\r\n this.generateVariants();\r\n });\r\n }\r\n\r\n private optionsAreEqual(a: Array<{ name: string }>, b: Array<{ name: string }>): boolean {\r\n return this.toOptionString(a) === this.toOptionString(b);\r\n }\r\n\r\n private optionsAreSubset(a: Array<{ name: string }>, b: Array<{ name: string }>): boolean {\r\n return this.toOptionString(b).includes(this.toOptionString(a));\r\n }\r\n\r\n private toOptionString(o: Array<{ name: string }>): string {\r\n return o\r\n .map(x => x.name)\r\n .sort()\r\n .join('|');\r\n }\r\n}\r\n","import { Injectable } from '@angular/core';\r\nimport { Router } from '@angular/router';\r\nimport { AssetFragment, AssetType, BaseEntityResolver, DataService } from '@vendure/admin-ui/core';\r\n\r\n@Injectable({\r\n providedIn: 'root',\r\n})\r\nexport class AssetResolver extends BaseEntityResolver<AssetFragment> {\r\n constructor(router: Router, dataService: DataService) {\r\n super(\r\n router,\r\n {\r\n __typename: 'Asset' as const,\r\n id: '',\r\n createdAt: '',\r\n updatedAt: '',\r\n name: '',\r\n type: AssetType.IMAGE,\r\n fileSize: 0,\r\n mimeType: '',\r\n width: 0,\r\n height: 0,\r\n source: '',\r\n preview: '',\r\n focalPoint: null,\r\n },\r\n id => dataService.product.getAsset(id).mapStream(data => data.asset),\r\n );\r\n }\r\n}\r\n","import { Injectable } from '@angular/core';\r\nimport { Router } from '@angular/router';\r\nimport {\r\n BaseEntityResolver,\r\n CollectionFragment,\r\n DataService,\r\n getDefaultUiLanguage,\r\n} from '@vendure/admin-ui/core';\r\n\r\n@Injectable({\r\n providedIn: 'root',\r\n})\r\nexport class CollectionResolver extends BaseEntityResolver<CollectionFragment> {\r\n constructor(router: Router, dataService: DataService) {\r\n super(\r\n router,\r\n {\r\n __typename: 'Collection' as 'Collection',\r\n id: '',\r\n createdAt: '',\r\n updatedAt: '',\r\n languageCode: getDefaultUiLanguage(),\r\n name: '',\r\n slug: '',\r\n isPrivate: false,\r\n breadcrumbs: [],\r\n description: '',\r\n featuredAsset: null,\r\n assets: [],\r\n translations: [],\r\n inheritFilters: true,\r\n filters: [],\r\n parent: {} as any,\r\n children: null,\r\n },\r\n id => dataService.collection.getCollection(id).mapStream(data => data.collection),\r\n );\r\n }\r\n}\r\n","import { Injectable } from '@angular/core';\r\nimport { Router } from '@angular/router';\r\nimport {\r\n BaseEntityResolver,\r\n DataService,\r\n FacetWithValuesFragment,\r\n getDefaultUiLanguage,\r\n} from '@vendure/admin-ui/core';\r\n\r\n@Injectable({\r\n providedIn: 'root',\r\n})\r\nexport class FacetResolver extends BaseEntityResolver<FacetWithValuesFragment> {\r\n constructor(router: Router, dataService: DataService) {\r\n super(\r\n router,\r\n {\r\n __typename: 'Facet' as 'Facet',\r\n id: '',\r\n createdAt: '',\r\n updatedAt: '',\r\n isPrivate: false,\r\n languageCode: getDefaultUiLanguage(),\r\n name: '',\r\n code: '',\r\n translations: [],\r\n values: [],\r\n },\r\n id => dataService.facet.getFacet(id).mapStream(data => data.facet),\r\n );\r\n }\r\n}\r\n","import { Injectable } from '@angular/core';\r\nimport { Router } from '@angular/router';\r\nimport {\r\n BaseEntityResolver,\r\n DataService,\r\n getDefaultUiLanguage,\r\n GetProductWithVariantsQuery,\r\n} from '@vendure/admin-ui/core';\r\n\r\n@Injectable({\r\n providedIn: 'root',\r\n})\r\nexport class ProductResolver extends BaseEntityResolver<GetProductWithVariantsQuery['product']> {\r\n constructor(dataService: DataService, router: Router) {\r\n super(\r\n router,\r\n {\r\n __typename: 'Product' as 'Product',\r\n id: '',\r\n createdAt: '',\r\n updatedAt: '',\r\n enabled: true,\r\n languageCode: getDefaultUiLanguage(),\r\n name: '',\r\n slug: '',\r\n featuredAsset: null,\r\n assets: [],\r\n description: '',\r\n translations: [],\r\n optionGroups: [],\r\n facetValues: [],\r\n variantList: { items: [], totalItems: 0 },\r\n channels: [],\r\n },\r\n id =>\r\n dataService.product\r\n .getProduct(id, { take: 10 })\r\n .refetchOnChannelChange()\r\n .mapStream(data => data.product),\r\n );\r\n }\r\n}\r\n","import { Injectable } from '@angular/core';\r\nimport { Router } from '@angular/router';\r\nimport { BaseEntityResolver } from '@vendure/admin-ui/core';\r\nimport { GetProductVariantOptionsQuery } from '@vendure/admin-ui/core';\r\nimport { DataService } from '@vendure/admin-ui/core';\r\n\r\n@Injectable({\r\n providedIn: 'root',\r\n})\r\nexport class ProductVariantsResolver extends BaseEntityResolver<GetProductVariantOptionsQuery['product']> {\r\n constructor(router: Router, dataService: DataService) {\r\n super(\r\n router,\r\n {\r\n __typename: 'Product' as 'Product',\r\n id: '',\r\n createdAt: '',\r\n updatedAt: '',\r\n name: '',\r\n optionGroups: [],\r\n variants: [],\r\n },\r\n id => dataService.product.getProductVariantsOptions(id).mapStream(data => data.product),\r\n );\r\n }\r\n}\r\n","import { Route } from '@angular/router';\r\nimport { marker as _ } from '@biesbjerg/ngx-translate-extract-marker';\r\nimport {\r\n AssetFragment,\r\n CanDeactivateDetailGuard,\r\n CollectionFragment,\r\n createResolveData,\r\n detailBreadcrumb,\r\n FacetWithValuesFragment,\r\n GetProductWithVariantsQuery,\r\n} from '@vendure/admin-ui/core';\r\nimport { map } from 'rxjs/operators';\r\n\r\nimport { AssetDetailComponent } from './components/asset-detail/asset-detail.component';\r\nimport { AssetListComponent } from './components/asset-list/asset-list.component';\r\nimport { CollectionDetailComponent } from './components/collection-detail/collection-detail.component';\r\nimport { CollectionListComponent } from './components/collection-list/collection-list.component';\r\nimport { FacetDetailComponent } from './components/facet-detail/facet-detail.component';\r\nimport { FacetListComponent } from './components/facet-list/facet-list.component';\r\nimport { ProductDetailComponent } from './components/product-detail/product-detail.component';\r\nimport { ProductListComponent } from './components/product-list/product-list.component';\r\nimport { ProductOptionsEditorComponent } from './components/product-options-editor/product-options-editor.component';\r\nimport { ProductVariantsEditorComponent } from './components/product-variants-editor/product-variants-editor.component';\r\nimport { AssetResolver } from './providers/routing/asset-resolver';\r\nimport { CollectionResolver } from './providers/routing/collection-resolver';\r\nimport { FacetResolver } from './providers/routing/facet-resolver';\r\nimport { ProductResolver } from './providers/routing/product-resolver';\r\nimport { ProductVariantsResolver } from './providers/routing/product-variants-resolver';\r\n\r\nexport const catalogRoutes: Route[] = [\r\n {\r\n path: 'products',\r\n component: ProductListComponent,\r\n data: {\r\n breadcrumb: _('breadcrumb.products'),\r\n },\r\n },\r\n {\r\n path: 'products/:id',\r\n component: ProductDetailComponent,\r\n resolve: createResolveData(ProductResolver),\r\n canDeactivate: [CanDeactivateDetailGuard],\r\n data: {\r\n breadcrumb: productBreadcrumb,\r\n },\r\n },\r\n {\r\n path: 'products/:id/manage-variants',\r\n component: ProductVariantsEditorComponent,\r\n resolve: createResolveData(ProductVariantsResolver),\r\n canDeactivate: [CanDeactivateDetailGuard],\r\n data: {\r\n breadcrumb: productVariantEditorBreadcrumb,\r\n },\r\n },\r\n {\r\n path: 'products/:id/options',\r\n component: ProductOptionsEditorComponent,\r\n resolve: createResolveData(ProductVariantsResolver),\r\n canDeactivate: [CanDeactivateDetailGuard],\r\n data: {\r\n breadcrumb: productOptionsEditorBreadcrumb,\r\n },\r\n },\r\n {\r\n path: 'facets',\r\n component: FacetListComponent,\r\n data: {\r\n breadcrumb: _('breadcrumb.facets'),\r\n },\r\n },\r\n {\r\n path: 'facets/:id',\r\n component: FacetDetailComponent,\r\n resolve: createResolveData(FacetResolver),\r\n canDeactivate: [CanDeactivateDetailGuard],\r\n data: {\r\n breadcrumb: facetBreadcrumb,\r\n },\r\n },\r\n {\r\n path: 'collections',\r\n component: CollectionListComponent,\r\n data: {\r\n breadcrumb: _('breadcrumb.collections'),\r\n },\r\n },\r\n {\r\n path: 'collections/:id',\r\n component: CollectionDetailComponent,\r\n resolve: createResolveData(CollectionResolver),\r\n canDeactivate: [CanDeactivateDetailGuard],\r\n data: {\r\n breadcrumb: collectionBreadcrumb,\r\n },\r\n },\r\n {\r\n path: 'assets',\r\n component: AssetListComponent,\r\n data: {\r\n breadcrumb: _('breadcrumb.assets'),\r\n },\r\n },\r\n {\r\n path: 'assets/:id',\r\n component: AssetDetailComponent,\r\n resolve: createResolveData(AssetResolver),\r\n data: {\r\n breadcrumb: assetBreadcrumb,\r\n },\r\n },\r\n];\r\n\r\nexport function productBreadcrumb(data: any, params: any) {\r\n return detailBreadcrumb<NonNullable<GetProductWithVariantsQuery['product']>>({\r\n entity: data.entity,\r\n id: params.id,\r\n breadcrumbKey: 'breadcrumb.products',\r\n getName: product => product.name,\r\n route: 'products',\r\n });\r\n}\r\n\r\nexport function productVariantEditorBreadcrumb(data: any, params: any) {\r\n return data.entity.pipe(\r\n map((entity: any) => {\r\n return [\r\n {\r\n label: _('breadcrumb.products'),\r\n link: ['../', 'products'],\r\n },\r\n {\r\n label: `${entity.name}`,\r\n link: ['../', 'products', params.id, { tab: 'variants' }],\r\n },\r\n {\r\n label: _('breadcrumb.manage-variants'),\r\n link: ['manage-variants'],\r\n },\r\n ];\r\n }),\r\n );\r\n}\r\n\r\nexport function productOptionsEditorBreadcrumb(data: any, params: any) {\r\n return data.entity.pipe(\r\n map((entity: any) => {\r\n return [\r\n {\r\n label: _('breadcrumb.products'),\r\n link: ['../', 'products'],\r\n },\r\n {\r\n label: `${entity.name}`,\r\n link: ['../', 'products', params.id, { tab: 'variants' }],\r\n },\r\n {\r\n label: _('breadcrumb.product-options'),\r\n link: ['options'],\r\n },\r\n ];\r\n }),\r\n );\r\n}\r\n\r\nexport function facetBreadcrumb(data: any, params: any) {\r\n return detailBreadcrumb<FacetWithValuesFragment>({\r\n entity: data.entity,\r\n id: params.id,\r\n breadcrumbKey: 'breadcrumb.facets',\r\n getName: facet => facet.name,\r\n route: 'facets',\r\n });\r\n}\r\n\r\nexport function collectionBreadcrumb(data: any, params: any) {\r\n return detailBreadcrumb<CollectionFragment>({\r\n entity: data.entity,\r\n id: params.id,\r\n breadcrumbKey: 'breadcrumb.collections',\r\n getName: collection => collection.name,\r\n route: 'collections',\r\n });\r\n}\r\n\r\nexport function assetBreadcrumb(data: any, params: any) {\r\n return detailBreadcrumb<AssetFragment>({\r\n entity: data.entity,\r\n id: params.id,\r\n breadcrumbKey: 'breadcrumb.assets',\r\n getName: asset => asset.name,\r\n route: 'assets',\r\n });\r\n}\r\n","<ng-template vdrDialogTitle>\r\n {{ 'catalog.assign-to-channel' | translate }}\r\n</ng-template>\r\n<clr-input-container class=\"mb4\">\r\n <label>{{ 'common.channel' | translate }}</label>\r\n <vdr-channel-assignment-control\r\n clrInput\r\n [multiple]=\"false\"\r\n [includeDefaultChannel]=\"false\"\r\n [formControl]=\"selectedChannelIdControl\"\r\n ></vdr-channel-assignment-control>\r\n</clr-input-container>\r\n\r\n<ng-template vdrDialogButtons>\r\n <button type=\"button\" class=\"btn\" (click)=\"cancel()\">{{ 'common.cancel' | translate }}</button>\r\n <button type=\"submit\" (click)=\"assign()\" [disabled]=\"!selectedChannel\" class=\"btn btn-primary\">\r\n <ng-template [ngIf]=\"selectedChannel\" [ngIfElse]=\"noSelection\">\r\n {{ 'catalog.assign-to-named-channel' | translate: { channelCode: selectedChannel?.code } }}\r\n </ng-template>\r\n <ng-template #noSelection>\r\n {{ 'catalog.no-channel-selected' | translate }}\r\n </ng-template>\r\n </button>\r\n</ng-template>\r\n","import { ChangeDetectionStrategy, Component, OnInit } from '@angular/core';\r\nimport { FormControl } from '@angular/forms';\r\nimport { DataService, Dialog, GetChannelsQuery, ItemOf, NotificationService } from '@vendure/admin-ui/core';\r\nimport { combineLatest } from 'rxjs';\r\n\r\ntype Channel = GetChannelsQuery['channels'][number];\r\n\r\n@Component({\r\n selector: 'vdr-assign-to-channel-dialog',\r\n templateUrl: './assign-to-channel-dialog.component.html',\r\n styleUrls: ['./assign-to-channel-dialog.component.scss'],\r\n changeDetection: ChangeDetectionStrategy.OnPush,\r\n})\r\nexport class AssignToChannelDialogComponent implements OnInit, Dialog<Channel> {\r\n selectedChannel: Channel | null | undefined;\r\n currentChannel: Channel;\r\n availableChannels: Channel[];\r\n resolveWith: (result?: Channel) => void;\r\n selectedChannelIdControl = new FormControl();\r\n\r\n // assigned by ModalService.fromComponent() call\r\n\r\n constructor(private dataService: DataService, private notificationService: NotificationService) {}\r\n\r\n ngOnInit() {\r\n const activeChannelId$ = this.dataService.client\r\n .userStatus()\r\n .mapSingle(({ userStatus }) => userStatus.activeChannelId);\r\n const allChannels$ = this.dataService.settings.getChannels().mapSingle(data => data.channels);\r\n\r\n combineLatest(activeChannelId$, allChannels$).subscribe(([activeChannelId, channels]) => {\r\n // tslint:disable-next-line:no-non-null-assertion\r\n this.currentChannel = channels.find(c => c.id === activeChannelId)!;\r\n this.availableChannels = channels;\r\n });\r\n\r\n this.selectedChannelIdControl.valueChanges.subscribe(ids => {\r\n this.selectChannel(ids);\r\n });\r\n }\r\n\r\n selectChannel(channelIds: string[]) {\r\n this.selectedChannel = this.availableChannels.find(c => c.id === channelIds[0]);\r\n }\r\n\r\n assign() {\r\n const selectedChannel = this.selectedChannel;\r\n if (selectedChannel) {\r\n this.resolveWith(selectedChannel);\r\n }\r\n }\r\n\r\n cancel() {\r\n this.resolveWith();\r\n }\r\n}\r\n","import { gql } from 'apollo-angular';\r\n\r\nexport const GET_PRODUCTS_WITH_FACET_VALUES_BY_IDS = gql`\r\n query GetProductsWithFacetValuesByIds($ids: [String!]!) {\r\n products(options: { filter: { id: { in: $ids } } }) {\r\n items {\r\n id\r\n name\r\n facetValues {\r\n id\r\n name\r\n code\r\n facet {\r\n id\r\n name\r\n code\r\n }\r\n }\r\n }\r\n }\r\n }\r\n`;\r\n\r\nexport const GET_VARIANTS_WITH_FACET_VALUES_BY_IDS = gql`\r\n query GetVariantsWithFacetValuesByIds($ids: [String!]!) {\r\n productVariants(options: { filter: { id: { in: $ids } } }) {\r\n items {\r\n id\r\n name\r\n sku\r\n facetValues {\r\n id\r\n name\r\n code\r\n facet {\r\n id\r\n name\r\n code\r\n }\r\n }\r\n }\r\n }\r\n }\r\n`;\r\n\r\nexport const UPDATE_PRODUCTS_BULK = gql`\r\n mutation UpdateProductsBulk($input: [UpdateProductInput!]!) {\r\n updateProducts(input: $input) {\r\n id\r\n name\r\n facetValues {\r\n id\r\n name\r\n code\r\n }\r\n }\r\n }\r\n`;\r\n\r\nexport const UPDATE_VARIANTS_BULK = gql`\r\n mutation UpdateVariantsBulk($input: [UpdateProductVariantInput!]!) {\r\n updateProductVariants(input: $input) {\r\n id\r\n name\r\n facetValues {\r\n id\r\n name\r\n code\r\n }\r\n }\r\n }\r\n`;\r\n","<ng-template vdrDialogTitle>\r\n {{ 'catalog.edit-facet-values' | translate }}\r\n</ng-template>\r\n\r\n<div class=\"flex\">\r\n <div class=\"flex center\">\r\n <div class=\"mr2\">\r\n {{ 'catalog.add-facet-value' | translate }}\r\n </div>\r\n <vdr-facet-value-selector\r\n (selectedValuesChange)=\"selectedValues = $event\"\r\n ></vdr-facet-value-selector>\r\n </div>\r\n</div>\r\n\r\n<table class=\"table\" *ngIf=\"state !== 'loading'; else placeholder\">\r\n <tbody>\r\n <tr *ngFor=\"let item of items\">\r\n <td class=\"left align-middle\">\r\n <div>{{ item.name }}</div>\r\n <div *ngIf=\"item.sku\" class=\"sku\">{{ item.sku }}</div>\r\n </td>\r\n <td class=\"left\">\r\n <vdr-facet-value-chip\r\n *ngFor=\"let facetValue of item.facetValues\"\r\n [facetValue]=\"facetValue\"\r\n (remove)=\"removeFacetValue(item, facetValue.id)\"\r\n ></vdr-facet-value-chip>\r\n </td>\r\n </tr>\r\n </tbody>\r\n</table>\r\n\r\n<ng-template #placeholder>\r\n <div class=\"loading\">\r\n <clr-spinner></clr-spinner>\r\n </div>\r\n</ng-template>\r\n\r\n<ng-template vdrDialogButtons>\r\n <button type=\"button\" class=\"btn\" (click)=\"cancel()\">{{ 'common.cancel' | translate }}</button>\r\n <button\r\n type=\"submit\"\r\n (click)=\"addFacetValues()\"\r\n [disabled]=\"selectedValues.length === 0 && facetValuesRemoved === false\"\r\n class=\"btn btn-primary\"\r\n >\r\n {{ 'common.update' | translate }}\r\n </button>\r\n</ng-template>\r\n","import { ChangeDetectionStrategy, ChangeDetectorRef, Component, OnDestroy, OnInit } from '@angular/core';\r\nimport {\r\n DataService,\r\n Dialog,\r\n FacetWithValuesFragment,\r\n GetProductsWithFacetValuesByIdsQuery,\r\n GetProductsWithFacetValuesByIdsQueryVariables,\r\n GetVariantsWithFacetValuesByIdsQuery,\r\n UpdateProductsBulkMutation,\r\n UpdateProductsBulkMutationVariables,\r\n UpdateVariantsBulkMutation,\r\n UpdateVariantsBulkMutationVariables,\r\n} from '@vendure/admin-ui/core';\r\nimport { unique } from '@vendure/common/lib/unique';\r\nimport { Observable, Subscription } from 'rxjs';\r\nimport { shareReplay, switchMap } from 'rxjs/operators';\r\n\r\nimport {\r\n GET_PRODUCTS_WITH_FACET_VALUES_BY_IDS,\r\n GET_VARIANTS_WITH_FACET_VALUES_BY_IDS,\r\n UPDATE_PRODUCTS_BULK,\r\n UPDATE_VARIANTS_BULK,\r\n} from './bulk-add-facet-values-dialog.graphql';\r\n\r\ninterface ProductOrVariant {\r\n id: string;\r\n name: string;\r\n sku?: string;\r\n facetValues: Array<{\r\n id: string;\r\n name: string;\r\n code: string;\r\n facet: Array<{\r\n id: string;\r\n name: string;\r\n code: string;\r\n }>;\r\n }>;\r\n}\r\n\r\n@Component({\r\n selector: 'vdr-bulk-add-facet-values-dialog',\r\n templateUrl: './bulk-add-facet-values-dialog.component.html',\r\n styleUrls: ['./bulk-add-facet-values-dialog.component.scss'],\r\n changeDetection: ChangeDetectionStrategy.OnPush,\r\n})\r\nexport class BulkAddFacetValuesDialogComponent\r\n implements OnInit, OnDestroy, Dialog<FacetWithValuesFragment[]>\r\n{\r\n resolveWith: (result?: FacetWithValuesFragment[]) => void;\r\n /* provided by call to ModalService */\r\n mode: 'product' | 'variant' = 'product';\r\n ids?: string[];\r\n state: 'loading' | 'ready' | 'saving' = 'loading';\r\n\r\n selectedValues: FacetWithValuesFragment[] = [];\r\n items: ProductOrVariant[] = [];\r\n facetValuesRemoved = false;\r\n private subscription: Subscription;\r\n constructor(private dataService: DataService, private changeDetectorRef: ChangeDetectorRef) {}\r\n\r\n ngOnInit(): void {\r\n const fetchData$: Observable<any> =\r\n this.mode === 'product'\r\n ? this.dataService\r\n .query<\r\n GetProductsWithFacetValuesByIdsQuery,\r\n GetProductsWithFacetValuesByIdsQueryVariables\r\n >(GET_PRODUCTS_WITH_FACET_VALUES_BY_IDS, {\r\n ids: this.ids ?? [],\r\n })\r\n .mapSingle(({ products }) =>\r\n products.items.map(p => ({ ...p, facetValues: [...p.facetValues] })),\r\n )\r\n : this.dataService\r\n .query<\r\n GetVariantsWithFacetValuesByIdsQuery,\r\n GetProductsWithFacetValuesByIdsQueryVariables\r\n >(GET_VARIANTS_WITH_FACET_VALUES_BY_IDS, {\r\n ids: this.ids ?? [],\r\n })\r\n .mapSingle(({ productVariants }) =>\r\n productVariants.items.map(p => ({ ...p, facetValues: [...p.facetValues] })),\r\n );\r\n this.subscription = fetchData$.subscribe({\r\n next: items => {\r\n this.items = items;\r\n this.state = 'ready';\r\n this.changeDetectorRef.markForCheck();\r\n },\r\n });\r\n }\r\n\r\n ngOnDestroy() {\r\n this.subscription?.unsubscribe();\r\n }\r\n\r\n cancel() {\r\n this.resolveWith();\r\n }\r\n\r\n removeFacetValue(item: ProductOrVariant, facetValueId: string) {\r\n item.facetValues = item.facetValues.filter(fv => fv.id !== facetValueId);\r\n this.facetValuesRemoved = true;\r\n }\r\n\r\n addFacetValues() {\r\n const selectedFacetValueIds = this.selectedValues.map(sv => sv.id);\r\n this.state = 'saving';\r\n const save$: Observable<any> =\r\n this.mode === 'product'\r\n ? this.dataService.mutate<UpdateProductsBulkMutation, UpdateProductsBulkMutationVariables>(\r\n UPDATE_PRODUCTS_BULK,\r\n {\r\n input: this.items?.map(product => ({\r\n id: product.id,\r\n facetValueIds: unique([\r\n ...product.facetValues.map(fv => fv.id),\r\n ...selectedFacetValueIds,\r\n ]),\r\n })),\r\n },\r\n )\r\n : this.dataService.mutate<UpdateVariantsBulkMutation, UpdateVariantsBulkMutationVariables>(\r\n UPDATE_VARIANTS_BULK,\r\n {\r\n input: this.items?.map(product => ({\r\n id: product.id,\r\n facetValueIds: unique([\r\n ...product.facetValues.map(fv => fv.id),\r\n ...selectedFacetValueIds,\r\n ]),\r\n })),\r\n },\r\n );\r\n return save$.subscribe(result => {\r\n this.resolveWith(this.selectedValues);\r\n });\r\n }\r\n}\r\n","import { marker as _ } from '@biesbjerg/ngx-translate-extract-marker';\r\nimport {\r\n BulkAction,\r\n currentChannelIsNotDefault,\r\n DataService,\r\n DeletionResult,\r\n getChannelCodeFromUserStatus,\r\n isMultiChannel,\r\n ModalService,\r\n NotificationService,\r\n Permission,\r\n} from '@vendure/admin-ui/core';\r\nimport { unique } from '@vendure/common/lib/unique';\r\nimport { EMPTY, from, of } from 'rxjs';\r\nimport { mapTo, switchMap } from 'rxjs/operators';\r\n\r\nimport { AssignToChannelDialogComponent } from '../assign-to-channel-dialog/assign-to-channel-dialog.component';\r\nimport { CollectionPartial } from '../collection-tree/collection-tree.types';\r\n\r\nimport { CollectionListComponent } from './collection-list.component';\r\n\r\nexport const deleteCollectionsBulkAction: BulkAction<CollectionPartial, CollectionListComponent> = {\r\n location: 'collection-list',\r\n label: _('common.delete'),\r\n icon: 'trash',\r\n iconClass: 'is-danger',\r\n requiresPermission: userPermissions =>\r\n userPermissions.includes(Permission.DeleteCollection) ||\r\n userPermissions.includes(Permission.DeleteCatalog),\r\n onClick: ({ injector, selection, hostComponent, clearSelection }) => {\r\n const modalService = injector.get(ModalService);\r\n const dataService = injector.get(DataService);\r\n const notificationService = injector.get(NotificationService);\r\n\r\n modalService\r\n .dialog({\r\n title: _('catalog.confirm-bulk-delete-collections'),\r\n translationVars: {\r\n count: selection.length,\r\n },\r\n buttons: [\r\n { type: 'secondary', label: _('common.cancel') },\r\n { type: 'danger', label: _('common.delete'), returnValue: true },\r\n ],\r\n })\r\n .pipe(\r\n switchMap(response =>\r\n response\r\n ? dataService.collection.deleteCollections(unique(selection.map(c => c.id)))\r\n : EMPTY,\r\n ),\r\n )\r\n .subscribe(result => {\r\n let deleted = 0;\r\n const errors: string[] = [];\r\n for (const item of result.deleteCollections) {\r\n if (item.result === DeletionResult.DELETED) {\r\n deleted++;\r\n } else if (item.message) {\r\n errors.push(item.message);\r\n }\r\n }\r\n if (0 < deleted) {\r\n notificationService.success(_('catalog.notify-bulk-delete-collections-success'), {\r\n count: deleted,\r\n });\r\n }\r\n if (0 < errors.length) {\r\n notificationService.error(errors.join('\\n'));\r\n }\r\n hostComponent.refresh();\r\n clearSelection();\r\n });\r\n },\r\n};\r\n\r\nexport const assignCollectionsToChannelBulkAction: BulkAction<CollectionPartial, CollectionListComponent> = {\r\n location: 'collection-list',\r\n label: _('catalog.assign-to-channel'),\r\n icon: 'layers',\r\n requiresPermission: userPermissions =>\r\n userPermissions.includes(Permission.UpdateCatalog) ||\r\n userPermissions.includes(Permission.UpdateProduct),\r\n isVisible: ({ injector }) => isMultiChannel(injector.get(DataService)),\r\n onClick: ({ injector, selection, hostComponent, clearSelection }) => {\r\n const modalService = injector.get(ModalService);\r\n const dataService = injector.get(DataService);\r\n const notificationService = injector.get(NotificationService);\r\n modalService\r\n .fromComponent(AssignToChannelDialogComponent, {\r\n size: 'md',\r\n locals: {},\r\n })\r\n .pipe(\r\n switchMap(result => {\r\n if (result) {\r\n return dataService.collection\r\n .assignCollectionsToChannel({\r\n collectionIds: selection.map(c => c.id),\r\n channelId: result.id,\r\n })\r\n .pipe(mapTo(result));\r\n } else {\r\n return EMPTY;\r\n }\r\n }),\r\n )\r\n .subscribe(result => {\r\n notificationService.success(_('catalog.assign-collections-to-channel-success'), {\r\n count: selection.length,\r\n channelCode: result.code,\r\n });\r\n clearSelection();\r\n });\r\n },\r\n};\r\n\r\nexport const removeCollectionsFromChannelBulkAction: BulkAction<CollectionPartial, CollectionListComponent> =\r\n {\r\n location: 'collection-list',\r\n label: _('catalog.remove-from-channel'),\r\n requiresPermission: userPermissions =>\r\n userPermissions.includes(Permission.UpdateChannel) ||\r\n userPermissions.includes(Permission.UpdateProduct),\r\n getTranslationVars: ({ injector }) => getChannelCodeFromUserStatus(injector.get(DataService)),\r\n icon: 'layers',\r\n iconClass: 'is-warning',\r\n isVisible: ({ injector }) => currentChannelIsNotDefault(injector.get(DataService)),\r\n onClick: ({ injector, selection, hostComponent, clearSelection }) => {\r\n const modalService = injector.get(ModalService);\r\n const dataService = injector.get(DataService);\r\n const notificationService = injector.get(NotificationService);\r\n const activeChannelId$ = dataService.client\r\n .userStatus()\r\n .mapSingle(({ userStatus }) => userStatus.activeChannelId);\r\n\r\n from(getChannelCodeFromUserStatus(injector.get(DataService)))\r\n .pipe(\r\n switchMap(({ channelCode }) =>\r\n modalService.dialog({\r\n title: _('catalog.remove-from-channel'),\r\n translationVars: {\r\n channelCode,\r\n },\r\n buttons: [\r\n { type: 'secondary', label: _('common.cancel') },\r\n {\r\n type: 'danger',\r\n label: _('common.remove'),\r\n returnValue: true,\r\n },\r\n ],\r\n }),\r\n ),\r\n switchMap(res =>\r\n res\r\n ? activeChannelId$.pipe(\r\n switchMap(activeChannelId =>\r\n activeChannelId\r\n ? dataService.collection.removeCollectionsFromChannel({\r\n channelId: activeChannelId,\r\n collectionIds: selection.map(c => c.id),\r\n })\r\n : EMPTY,\r\n ),\r\n mapTo(true),\r\n )\r\n : of(false),\r\n ),\r\n )\r\n .subscribe(removed => {\r\n if (removed) {\r\n clearSelection();\r\n notificationService.success(\r\n _('catalog.notify-remove-collections-from-channel-success'),\r\n {\r\n count: selection.length,\r\n },\r\n );\r\n hostComponent.refresh();\r\n }\r\n });\r\n },\r\n };\r\n","import { marker as _ } from '@biesbjerg/ngx-translate-extract-marker';\r\nimport {\r\n BulkAction,\r\n currentChannelIsNotDefault,\r\n DataService,\r\n DeletionResult,\r\n getChannelCodeFromUserStatus,\r\n GetFacetListQuery,\r\n isMultiChannel,\r\n ItemOf,\r\n ModalService,\r\n NotificationService,\r\n Permission,\r\n} from '@vendure/admin-ui/core';\r\nimport { unique } from '@vendure/common/lib/unique';\r\nimport { EMPTY, of } from 'rxjs';\r\nimport { map, mapTo, switchMap } from 'rxjs/operators';\r\n\r\nimport { AssignToChannelDialogComponent } from '../assign-to-channel-dialog/assign-to-channel-dialog.component';\r\n\r\nimport { FacetListComponent } from './facet-list.component';\r\n\r\nexport const deleteFacetsBulkAction: BulkAction<ItemOf<GetFacetListQuery, 'facets'>, FacetListComponent> = {\r\n location: 'facet-list',\r\n label: _('common.delete'),\r\n icon: 'trash',\r\n iconClass: 'is-danger',\r\n requiresPermission: userPermissions =>\r\n userPermissions.includes(Permission.DeleteFacet) ||\r\n userPermissions.includes(Permission.DeleteCatalog),\r\n onClick: ({ injector, selection, hostComponent, clearSelection }) => {\r\n const modalService = injector.get(ModalService);\r\n const dataService = injector.get(DataService);\r\n const notificationService = injector.get(NotificationService);\r\n\r\n function showModalAndDelete(facetIds: string[], message?: string) {\r\n return modalService\r\n .dialog({\r\n title: _('catalog.confirm-bulk-delete-facets'),\r\n translationVars: {\r\n count: selection.length,\r\n },\r\n size: message ? 'lg' : 'md',\r\n body: message,\r\n buttons: [\r\n { type: 'secondary', label: _('common.cancel') },\r\n {\r\n type: 'danger',\r\n label: message ? _('common.force-delete') : _('common.delete'),\r\n returnValue: true,\r\n },\r\n ],\r\n })\r\n .pipe(\r\n switchMap(res =>\r\n res\r\n ? dataService.facet\r\n .deleteFacets(facetIds, !!message)\r\n .pipe(map(res2 => res2.deleteFacets))\r\n : of([]),\r\n ),\r\n );\r\n }\r\n\r\n showModalAndDelete(unique(selection.map(f => f.id)))\r\n .pipe(\r\n switchMap(result => {\r\n let deletedCount = 0;\r\n const errors: string[] = [];\r\n const errorIds: string[] = [];\r\n let i = 0;\r\n for (const item of result) {\r\n if (item.result === DeletionResult.DELETED) {\r\n deletedCount++;\r\n } else if (item.message) {\r\n errors.push(item.message);\r\n errorIds.push(selection[i]?.id);\r\n }\r\n i++;\r\n }\r\n if (0 < errorIds.length) {\r\n return showModalAndDelete(errorIds, errors.join('\\n')).pipe(\r\n map(result2 => {\r\n const deletedCount2 = result2.filter(\r\n r => r.result === DeletionResult.DELETED,\r\n ).length;\r\n return deletedCount + deletedCount2;\r\n }),\r\n );\r\n } else {\r\n return of(deletedCount);\r\n }\r\n }),\r\n )\r\n .subscribe(deletedCount => {\r\n if (deletedCount) {\r\n hostComponent.refresh();\r\n clearSelection();\r\n notificationService.success(_('catalog.notify-bulk-delete-facets-success'), {\r\n count: deletedCount,\r\n });\r\n }\r\n });\r\n },\r\n};\r\n\r\nexport const assignFacetsToChannelBulkAction: BulkAction<\r\n ItemOf<GetFacetListQuery, 'facets'>,\r\n FacetListComponent\r\n> = {\r\n location: 'facet-list',\r\n label: _('catalog.assign-to-channel'),\r\n icon: 'layers',\r\n requiresPermission: userPermissions =>\r\n userPermissions.includes(Permission.UpdateFacet) ||\r\n userPermissions.includes(Permission.UpdateCatalog),\r\n isVisible: ({ injector }) => isMultiChannel(injector.get(DataService)),\r\n onClick: ({ injector, selection, hostComponent, clearSelection }) => {\r\n const modalService = injector.get(ModalService);\r\n const dataService = injector.get(DataService);\r\n const notificationService = injector.get(NotificationService);\r\n modalService\r\n .fromComponent(AssignToChannelDialogComponent, {\r\n size: 'md',\r\n locals: {},\r\n })\r\n .pipe(\r\n switchMap(result => {\r\n if (result) {\r\n return dataService.facet\r\n .assignFacetsToChannel({\r\n facetIds: selection.map(f => f.id),\r\n channelId: result.id,\r\n })\r\n .pipe(mapTo(result));\r\n } else {\r\n return EMPTY;\r\n }\r\n }),\r\n )\r\n .subscribe(result => {\r\n notificationService.success(_('catalog.assign-facets-to-channel-success'), {\r\n count: selection.length,\r\n channelCode: result.code,\r\n });\r\n clearSelection();\r\n });\r\n },\r\n};\r\n\r\nexport const removeFacetsFromChannelBulkAction: BulkAction<\r\n ItemOf<GetFacetListQuery, 'facets'>,\r\n FacetListComponent\r\n> = {\r\n location: 'facet-list',\r\n label: _('catalog.remove-from-channel'),\r\n getTranslationVars: ({ injector }) => getChannelCodeFromUserStatus(injector.get(DataService)),\r\n icon: 'layers',\r\n iconClass: 'is-warning',\r\n requiresPermission: userPermissions =>\r\n userPermissions.includes(Permission.UpdateFacet) ||\r\n userPermissions.includes(Permission.UpdateCatalog),\r\n isVisible: ({ injector }) => currentChannelIsNotDefault(injector.get(DataService)),\r\n onClick: ({ injector, selection, hostComponent, clearSelection }) => {\r\n const modalService = injector.get(ModalService);\r\n const dataService = injector.get(DataService);\r\n const notificationService = injector.get(NotificationService);\r\n\r\n const activeChannelId$ = dataService.client\r\n .userStatus()\r\n .mapSingle(({ userStatus }) => userStatus.activeChannelId);\r\n\r\n function showModalAndDelete(facetIds: string[], message?: string) {\r\n return modalService\r\n .dialog({\r\n title: _('catalog.remove-from-channel'),\r\n translationVars: {\r\n count: selection.length,\r\n },\r\n size: message ? 'lg' : 'md',\r\n body: message,\r\n buttons: [\r\n { type: 'secondary', label: _('common.cancel') },\r\n {\r\n type: 'danger',\r\n label: message ? _('common.force-remove') : _('common.remove'),\r\n returnValue: true,\r\n },\r\n ],\r\n })\r\n .pipe(\r\n switchMap(res =>\r\n res\r\n ? activeChannelId$.pipe(\r\n switchMap(activeChannelId =>\r\n activeChannelId\r\n ? dataService.facet.removeFacetsFromChannel({\r\n channelId: activeChannelId,\r\n facetIds,\r\n force: !!message,\r\n })\r\n : EMPTY,\r\n ),\r\n map(res2 => res2.removeFacetsFromChannel),\r\n )\r\n : EMPTY,\r\n ),\r\n );\r\n }\r\n\r\n showModalAndDelete(unique(selection.map(f => f.id)))\r\n .pipe(\r\n switchMap(result => {\r\n let removedCount = selection.length;\r\n const errors: string[] = [];\r\n const errorIds: string[] = [];\r\n let i = 0;\r\n for (const item of result) {\r\n if (item.__typename === 'FacetInUseError') {\r\n errors.push(item.message);\r\n errorIds.push(selection[i]?.id);\r\n removedCount--;\r\n }\r\n i++;\r\n }\r\n if (0 < errorIds.length) {\r\n return showModalAndDelete(errorIds, errors.join('\\n')).pipe(\r\n map(result2 => {\r\n const notRemovedCount = result2.filter(\r\n r => r.__typename === 'FacetInUseError',\r\n ).length;\r\n return selection.length - notRemovedCount;\r\n }),\r\n );\r\n } else {\r\n return of(removedCount);\r\n }\r\n }),\r\n switchMap(removedCount =>\r\n removedCount\r\n ? getChannelCodeFromUserStatus(dataService).then(({ channelCode }) => ({\r\n channelCode,\r\n removedCount,\r\n }))\r\n : EMPTY,\r\n ),\r\n )\r\n .subscribe(({ removedCount, channelCode }) => {\r\n if (removedCount) {\r\n hostComponent.refresh();\r\n clearSelection();\r\n notificationService.success(_('catalog.notify-remove-facets-from-channel-success'), {\r\n count: removedCount,\r\n channelCode,\r\n });\r\n }\r\n });\r\n },\r\n};\r\n","import { marker as _ } from '@biesbjerg/ngx-translate-extract-marker';\r\nimport {\r\n BulkAction,\r\n currentChannelIsNotDefault,\r\n DataService,\r\n DeletionResult,\r\n getChannelCodeFromUserStatus,\r\n isMultiChannel,\r\n ModalService,\r\n NotificationService,\r\n Permission,\r\n} from '@vendure/admin-ui/core';\r\nimport { unique } from '@vendure/common/lib/unique';\r\nimport { EMPTY, from, of } from 'rxjs';\r\nimport { mapTo, switchMap } from 'rxjs/operators';\r\n\r\nimport { AssignProductsToChannelDialogComponent } from '../assign-products-to-channel-dialog/assign-products-to-channel-dialog.component';\r\nimport { BulkAddFacetValuesDialogComponent } from '../bulk-add-facet-values-dialog/bulk-add-facet-values-dialog.component';\r\n\r\nimport { ProductListComponent, SearchItem } from './product-list.component';\r\n\r\nexport const deleteProductsBulkAction: BulkAction<SearchItem, ProductListComponent> = {\r\n location: 'product-list',\r\n label: _('common.delete'),\r\n icon: 'trash',\r\n iconClass: 'is-danger',\r\n requiresPermission: userPermissions =>\r\n userPermissions.includes(Permission.DeleteProduct) ||\r\n userPermissions.includes(Permission.DeleteCatalog),\r\n onClick: ({ injector, selection, hostComponent, clearSelection }) => {\r\n const modalService = injector.get(ModalService);\r\n const dataService = injector.get(DataService);\r\n const notificationService = injector.get(NotificationService);\r\n modalService\r\n .dialog({\r\n title: _('catalog.confirm-bulk-delete-products'),\r\n translationVars: {\r\n count: selection.length,\r\n },\r\n buttons: [\r\n { type: 'secondary', label: _('common.cancel') },\r\n { type: 'danger', label: _('common.delete'), returnValue: true },\r\n ],\r\n })\r\n .pipe(\r\n switchMap(response =>\r\n response\r\n ? dataService.product.deleteProducts(unique(selection.map(p => p.productId)))\r\n : EMPTY,\r\n ),\r\n )\r\n .subscribe(result => {\r\n let deleted = 0;\r\n const errors: string[] = [];\r\n for (const item of result.deleteProducts) {\r\n if (item.result === DeletionResult.DELETED) {\r\n deleted++;\r\n } else if (item.message) {\r\n errors.push(item.message);\r\n }\r\n }\r\n if (0 < deleted) {\r\n notificationService.success(_('catalog.notify-bulk-delete-products-success'), {\r\n count: deleted,\r\n });\r\n }\r\n if (0 < errors.length) {\r\n notificationService.error(errors.join('\\n'));\r\n }\r\n hostComponent.refresh();\r\n clearSelection();\r\n });\r\n },\r\n};\r\n\r\nexport const assignProductsToChannelBulkAction: BulkAction<SearchItem, ProductListComponent> = {\r\n location: 'product-list',\r\n label: _('catalog.assign-to-channel'),\r\n icon: 'layers',\r\n requiresPermission: userPermissions =>\r\n userPermissions.includes(Permission.UpdateCatalog) ||\r\n userPermissions.includes(Permission.UpdateProduct),\r\n isVisible: ({ injector }) => isMultiChannel(injector.get(DataService)),\r\n onClick: ({ injector, selection, hostComponent, clearSelection }) => {\r\n const modalService = injector.get(ModalService);\r\n const dataService = injector.get(DataService);\r\n const notificationService = injector.get(NotificationService);\r\n modalService\r\n .fromComponent(AssignProductsToChannelDialogComponent, {\r\n size: 'lg',\r\n locals: {\r\n productIds: unique(selection.map(p => p.productId)),\r\n currentChannelIds: [],\r\n },\r\n })\r\n .subscribe(result => {\r\n if (result) {\r\n clearSelection();\r\n }\r\n });\r\n },\r\n};\r\n\r\nexport const removeProductsFromChannelBulkAction: BulkAction<SearchItem, ProductListComponent> = {\r\n location: 'product-list',\r\n label: _('catalog.remove-from-channel'),\r\n requiresPermission: userPermissions =>\r\n userPermissions.includes(Permission.UpdateChannel) ||\r\n userPermissions.includes(Permission.UpdateProduct),\r\n getTranslationVars: ({ injector }) => getChannelCodeFromUserStatus(injector.get(DataService)),\r\n icon: 'layers',\r\n iconClass: 'is-warning',\r\n isVisible: ({ injector }) => currentChannelIsNotDefault(injector.get(DataService)),\r\n onClick: ({ injector, selection, hostComponent, clearSelection }) => {\r\n const modalService = injector.get(ModalService);\r\n const dataService = injector.get(DataService);\r\n const notificationService = injector.get(NotificationService);\r\n const activeChannelId$ = dataService.client\r\n .userStatus()\r\n .mapSingle(({ userStatus }) => userStatus.activeChannelId);\r\n\r\n from(getChannelCodeFromUserStatus(injector.get(DataService)))\r\n .pipe(\r\n switchMap(({ channelCode }) =>\r\n modalService.dialog({\r\n title: _('catalog.remove-from-channel'),\r\n translationVars: {\r\n channelCode,\r\n },\r\n buttons: [\r\n { type: 'secondary', label: _('common.cancel') },\r\n {\r\n type: 'danger',\r\n label: _('common.remove'),\r\n returnValue: true,\r\n },\r\n ],\r\n }),\r\n ),\r\n switchMap(res =>\r\n res\r\n ? activeChannelId$.pipe(\r\n switchMap(activeChannelId =>\r\n activeChannelId\r\n ? dataService.product.removeProductsFromChannel({\r\n channelId: activeChannelId,\r\n productIds: selection.map(p => p.productId),\r\n })\r\n : EMPTY,\r\n ),\r\n mapTo(true),\r\n )\r\n : of(false),\r\n ),\r\n )\r\n .subscribe(removed => {\r\n if (removed) {\r\n clearSelection();\r\n notificationService.success(_('common.notify-remove-products-from-channel-success'), {\r\n count: selection.length,\r\n });\r\n setTimeout(() => hostComponent.refresh(), 1000);\r\n }\r\n });\r\n },\r\n};\r\n\r\nexport const assignFacetValuesToProductsBulkAction: BulkAction<SearchItem, ProductListComponent> = {\r\n location: 'product-list',\r\n label: _('catalog.edit-facet-values'),\r\n icon: 'tag',\r\n requiresPermission: userPermissions =>\r\n userPermissions.includes(Permission.UpdateCatalog) ||\r\n userPermissions.includes(Permission.UpdateProduct),\r\n onClick: ({ injector, selection, hostComponent, clearSelection }) => {\r\n const modalService = injector.get(ModalService);\r\n const dataService = injector.get(DataService);\r\n const notificationService = injector.get(NotificationService);\r\n const mode: 'product' | 'variant' = hostComponent.groupByProduct ? 'product' : 'variant';\r\n const ids =\r\n mode === 'product'\r\n ? unique(selection.map(p => p.productId))\r\n : unique(selection.map(p => p.productVariantId));\r\n return modalService\r\n .fromComponent(BulkAddFacetValuesDialogComponent, {\r\n size: 'xl',\r\n locals: {\r\n mode,\r\n ids,\r\n },\r\n })\r\n .subscribe(result => {\r\n if (result) {\r\n notificationService.success(_('common.notify-bulk-update-success'), {\r\n count: selection.length,\r\n entity: mode === 'product' ? 'Products' : 'ProductVariants',\r\n });\r\n clearSelection();\r\n }\r\n });\r\n },\r\n};\r\n","import { NgModule } from '@angular/core';\r\nimport { RouterModule } from '@angular/router';\r\nimport { BulkActionRegistryService, SharedModule } from '@vendure/admin-ui/core';\r\n\r\nimport { catalogRoutes } from './catalog.routes';\r\nimport { ApplyFacetDialogComponent } from './components/apply-facet-dialog/apply-facet-dialog.component';\r\nimport { AssetDetailComponent } from './components/asset-detail/asset-detail.component';\r\nimport { AssetListComponent } from './components/asset-list/asset-list.component';\r\nimport { AssetsComponent } from './components/assets/assets.component';\r\nimport { AssignProductsToChannelDialogComponent } from './components/assign-products-to-channel-dialog/assign-products-to-channel-dialog.component';\r\nimport { AssignToChannelDialogComponent } from './components/assign-to-channel-dialog/assign-to-channel-dialog.component';\r\nimport { BulkAddFacetValuesDialogComponent } from './components/bulk-add-facet-values-dialog/bulk-add-facet-values-dialog.component';\r\nimport { CollectionContentsComponent } from './components/collection-contents/collection-contents.component';\r\nimport { CollectionDetailComponent } from './components/collection-detail/collection-detail.component';\r\nimport {\r\n assignCollectionsToChannelBulkAction,\r\n deleteCollectionsBulkAction,\r\n removeCollectionsFromChannelBulkAction,\r\n} from './components/collection-list/collection-list-bulk-actions';\r\nimport { CollectionListComponent } from './components/collection-list/collection-list.component';\r\nimport { CollectionTreeNodeComponent } from './components/collection-tree/collection-tree-node.component';\r\nimport { CollectionTreeComponent } from './components/collection-tree/collection-tree.component';\r\nimport { ConfirmVariantDeletionDialogComponent } from './components/confirm-variant-deletion-dialog/confirm-variant-deletion-dialog.component';\r\nimport { FacetDetailComponent } from './components/facet-detail/facet-detail.component';\r\nimport {\r\n assignFacetsToChannelBulkAction,\r\n deleteFacetsBulkAction,\r\n removeFacetsFromChannelBulkAction,\r\n} from './components/facet-list/facet-list-bulk-actions';\r\nimport { FacetListComponent } from './components/facet-list/facet-list.component';\r\nimport { GenerateProductVariantsComponent } from './components/generate-product-variants/generate-product-variants.component';\r\nimport { OptionValueInputComponent } from './components/option-value-input/option-value-input.component';\r\nimport { ProductDetailComponent } from './components/product-detail/product-detail.component';\r\nimport {\r\n assignFacetValuesToProductsBulkAction,\r\n assignProductsToChannelBulkAction,\r\n deleteProductsBulkAction,\r\n removeProductsFromChannelBulkAction,\r\n} from './components/product-list/product-list-bulk-actions';\r\nimport { ProductListComponent } from './components/product-list/product-list.component';\r\nimport { ProductOptionsEditorComponent } from './components/product-options-editor/product-options-editor.component';\r\nimport { ProductVariantsEditorComponent } from './components/product-variants-editor/product-variants-editor.component';\r\nimport { ProductVariantsListComponent } from './components/product-variants-list/product-variants-list.component';\r\nimport { ProductVariantsTableComponent } from './components/product-variants-table/product-variants-table.component';\r\nimport { UpdateProductOptionDialogComponent } from './components/update-product-option-dialog/update-product-option-dialog.component';\r\nimport { VariantPriceDetailComponent } from './components/variant-price-detail/variant-price-detail.component';\r\n\r\nconst CATALOG_COMPONENTS = [\r\n ProductListComponent,\r\n ProductDetailComponent,\r\n FacetListComponent,\r\n FacetDetailComponent,\r\n GenerateProductVariantsComponent,\r\n ProductVariantsListComponent,\r\n ApplyFacetDialogComponent,\r\n AssetListComponent,\r\n AssetsComponent,\r\n VariantPriceDetailComponent,\r\n CollectionListComponent,\r\n CollectionDetailComponent,\r\n CollectionTreeComponent,\r\n CollectionTreeNodeComponent,\r\n CollectionContentsComponent,\r\n ProductVariantsTableComponent,\r\n OptionValueInputComponent,\r\n UpdateProductOptionDialogComponent,\r\n ProductVariantsEditorComponent,\r\n AssignProductsToChannelDialogComponent,\r\n AssetDetailComponent,\r\n ConfirmVariantDeletionDialogComponent,\r\n ProductOptionsEditorComponent,\r\n BulkAddFacetValuesDialogComponent,\r\n AssignToChannelDialogComponent,\r\n];\r\n\r\n@NgModule({\r\n imports: [SharedModule, RouterModule.forChild(catalogRoutes)],\r\n exports: [...CATALOG_COMPONENTS],\r\n declarations: [...CATALOG_COMPONENTS],\r\n})\r\nexport class CatalogModule {\r\n constructor(private bulkActionRegistryService: BulkActionRegistryService) {\r\n bulkActionRegistryService.registerBulkAction(assignFacetValuesToProductsBulkAction);\r\n bulkActionRegistryService.registerBulkAction(assignProductsToChannelBulkAction);\r\n bulkActionRegistryService.registerBulkAction(removeProductsFromChannelBulkAction);\r\n bulkActionRegistryService.registerBulkAction(deleteProductsBulkAction);\r\n\r\n bulkActionRegistryService.registerBulkAction(assignFacetsToChannelBulkAction);\r\n bulkActionRegistryService.registerBulkAction(removeFacetsFromChannelBulkAction);\r\n bulkActionRegistryService.registerBulkAction(deleteFacetsBulkAction);\r\n\r\n bulkActionRegistryService.registerBulkAction(assignCollectionsToChannelBulkAction);\r\n bulkActionRegistryService.registerBulkAction(removeCollectionsFromChannelBulkAction);\r\n bulkActionRegistryService.registerBulkAction(deleteCollectionsBulkAction);\r\n }\r\n}\r\n"],"sourceRoot":"webpack:///","file":"430.4469edebdd7335b3.js"}
|