comfyui-frontend-package 1.37.9__py3-none-any.whl → 1.37.11__py3-none-any.whl

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.
Files changed (188) hide show
  1. comfyui_frontend_package/static/assets/{AboutPanel-BudnQURa.js → AboutPanel-B-lCq9HV.js} +2 -2
  2. comfyui_frontend_package/static/assets/{AboutPanel-BudnQURa.js.map → AboutPanel-B-lCq9HV.js.map} +1 -1
  3. comfyui_frontend_package/static/assets/{AudioPreviewPlayer-CHjtFZRu.js → AudioPreviewPlayer-CXgr12AM.js} +2 -2
  4. comfyui_frontend_package/static/assets/{AudioPreviewPlayer-CHjtFZRu.js.map → AudioPreviewPlayer-CXgr12AM.js.map} +1 -1
  5. comfyui_frontend_package/static/assets/{ComfyQueueButton-QhN0FmOY.js → ComfyQueueButton-C6ttLtL6.js} +2 -2
  6. comfyui_frontend_package/static/assets/{ComfyQueueButton-QhN0FmOY.js.map → ComfyQueueButton-C6ttLtL6.js.map} +1 -1
  7. comfyui_frontend_package/static/assets/{ExtensionPanel-D2sITMri.js → ExtensionPanel-uFlj7Yfm.js} +2 -2
  8. comfyui_frontend_package/static/assets/{ExtensionPanel-D2sITMri.js.map → ExtensionPanel-uFlj7Yfm.js.map} +1 -1
  9. comfyui_frontend_package/static/assets/GraphView-0U0T8pwU.js +15 -0
  10. comfyui_frontend_package/static/assets/GraphView-0U0T8pwU.js.map +1 -0
  11. comfyui_frontend_package/static/assets/GraphView-2T90vQj0.css +1 -0
  12. comfyui_frontend_package/static/assets/{KeybindingPanel-Dm6H1RN2.js → KeybindingPanel-DtxoTOoX.js} +2 -2
  13. comfyui_frontend_package/static/assets/{KeybindingPanel-Dm6H1RN2.js.map → KeybindingPanel-DtxoTOoX.js.map} +1 -1
  14. comfyui_frontend_package/static/assets/LazyImage.vue_vue_type_script_setup_true_lang-BSzd4gKh.js +2 -0
  15. comfyui_frontend_package/static/assets/LazyImage.vue_vue_type_script_setup_true_lang-BSzd4gKh.js.map +1 -0
  16. comfyui_frontend_package/static/assets/{LegacyCreditsPanel-Be7L1Af3.js → LegacyCreditsPanel-CO0JRKfg.js} +2 -2
  17. comfyui_frontend_package/static/assets/{LegacyCreditsPanel-Be7L1Af3.js.map → LegacyCreditsPanel-CO0JRKfg.js.map} +1 -1
  18. comfyui_frontend_package/static/assets/{Load3D-BAJ3yM4D.js → Load3D-NG6IeknA.js} +2 -2
  19. comfyui_frontend_package/static/assets/Load3D-NG6IeknA.js.map +1 -0
  20. comfyui_frontend_package/static/assets/{Load3D.vue_vue_type_script_setup_true_lang-DMHpkO9N.js → Load3D.vue_vue_type_script_setup_true_lang-DYT5Ecka.js} +2 -2
  21. comfyui_frontend_package/static/assets/{Load3D.vue_vue_type_script_setup_true_lang-DMHpkO9N.js.map → Load3D.vue_vue_type_script_setup_true_lang-DYT5Ecka.js.map} +1 -1
  22. comfyui_frontend_package/static/assets/{Media3DTop-DdNgRlQW.js → Media3DTop-iLfJefgN.js} +2 -2
  23. comfyui_frontend_package/static/assets/{Media3DTop-DdNgRlQW.js.map → Media3DTop-iLfJefgN.js.map} +1 -1
  24. comfyui_frontend_package/static/assets/{ServerConfigPanel-LtRqEOzu.js → ServerConfigPanel-B8Qy2naY.js} +2 -2
  25. comfyui_frontend_package/static/assets/{ServerConfigPanel-LtRqEOzu.js.map → ServerConfigPanel-B8Qy2naY.js.map} +1 -1
  26. comfyui_frontend_package/static/assets/SubscriptionRequiredDialogContent-C1UryadQ.css +1 -0
  27. comfyui_frontend_package/static/assets/SubscriptionRequiredDialogContent-CIYbxFB5.js +2 -0
  28. comfyui_frontend_package/static/assets/{SubscriptionRequiredDialogContent-CDaF1jns.js.map → SubscriptionRequiredDialogContent-CIYbxFB5.js.map} +1 -1
  29. comfyui_frontend_package/static/assets/{UserAvatar.vue_vue_type_script_setup_true_lang-48WRCWXz.js → UserAvatar.vue_vue_type_script_setup_true_lang-COE-v4cY.js} +2 -2
  30. comfyui_frontend_package/static/assets/{UserAvatar.vue_vue_type_script_setup_true_lang-48WRCWXz.js.map → UserAvatar.vue_vue_type_script_setup_true_lang-COE-v4cY.js.map} +1 -1
  31. comfyui_frontend_package/static/assets/{UserPanel-_xK7KdbS.js → UserPanel-D5s95p9f.js} +2 -2
  32. comfyui_frontend_package/static/assets/{UserPanel-_xK7KdbS.js.map → UserPanel-D5s95p9f.js.map} +1 -1
  33. comfyui_frontend_package/static/assets/{UserSelectView-B_VOz5XU.js → UserSelectView-TWmqiRNC.js} +2 -2
  34. comfyui_frontend_package/static/assets/{UserSelectView-B_VOz5XU.js.map → UserSelectView-TWmqiRNC.js.map} +1 -1
  35. comfyui_frontend_package/static/assets/{ValueControlPopover-BPJIx3_y.js → ValueControlPopover-oFjRn7nT.js} +2 -2
  36. comfyui_frontend_package/static/assets/{ValueControlPopover-BPJIx3_y.js.map → ValueControlPopover-oFjRn7nT.js.map} +1 -1
  37. comfyui_frontend_package/static/assets/{WidgetAudioUI-5nP5sugf.js → WidgetAudioUI-DYG-X1jd.js} +2 -2
  38. comfyui_frontend_package/static/assets/{WidgetAudioUI-5nP5sugf.js.map → WidgetAudioUI-DYG-X1jd.js.map} +1 -1
  39. comfyui_frontend_package/static/assets/{WidgetButton-Cd9G_fIM.js → WidgetButton-pJqn_pIo.js} +2 -2
  40. comfyui_frontend_package/static/assets/{WidgetButton-Cd9G_fIM.js.map → WidgetButton-pJqn_pIo.js.map} +1 -1
  41. comfyui_frontend_package/static/assets/{WidgetChart-Dz4GcJwO.js → WidgetChart-BntGUEQZ.js} +2 -2
  42. comfyui_frontend_package/static/assets/{WidgetChart-Dz4GcJwO.js.map → WidgetChart-BntGUEQZ.js.map} +1 -1
  43. comfyui_frontend_package/static/assets/{WidgetColorPicker-x6uZPjSf.js → WidgetColorPicker-JIRhb2dg.js} +2 -2
  44. comfyui_frontend_package/static/assets/{WidgetColorPicker-x6uZPjSf.js.map → WidgetColorPicker-JIRhb2dg.js.map} +1 -1
  45. comfyui_frontend_package/static/assets/{WidgetGalleria-DHPc3hwg.js → WidgetGalleria-CtUTrKmF.js} +2 -2
  46. comfyui_frontend_package/static/assets/{WidgetGalleria-DHPc3hwg.js.map → WidgetGalleria-CtUTrKmF.js.map} +1 -1
  47. comfyui_frontend_package/static/assets/WidgetInputNumber-DPITONSH.js +2 -0
  48. comfyui_frontend_package/static/assets/WidgetInputNumber-DPITONSH.js.map +1 -0
  49. comfyui_frontend_package/static/assets/{WidgetInputNumber.vue_vue_type_script_setup_true_lang-vY96bQKz.js → WidgetInputNumber.vue_vue_type_script_setup_true_lang-Cb9Vjdsr.js} +2 -2
  50. comfyui_frontend_package/static/assets/{WidgetInputNumber.vue_vue_type_script_setup_true_lang-vY96bQKz.js.map → WidgetInputNumber.vue_vue_type_script_setup_true_lang-Cb9Vjdsr.js.map} +1 -1
  51. comfyui_frontend_package/static/assets/{WidgetInputText-BbfUME5C.js → WidgetInputText-C9e7Utok.js} +2 -2
  52. comfyui_frontend_package/static/assets/{WidgetInputText-BbfUME5C.js.map → WidgetInputText-C9e7Utok.js.map} +1 -1
  53. comfyui_frontend_package/static/assets/{WidgetLayoutField.vue_vue_type_script_setup_true_lang-7bIn_5fI.js → WidgetLayoutField.vue_vue_type_script_setup_true_lang-B2h9BxrZ.js} +2 -2
  54. comfyui_frontend_package/static/assets/{WidgetLayoutField.vue_vue_type_script_setup_true_lang-7bIn_5fI.js.map → WidgetLayoutField.vue_vue_type_script_setup_true_lang-B2h9BxrZ.js.map} +1 -1
  55. comfyui_frontend_package/static/assets/WidgetLegacy-DxWXa1q8.js +2 -0
  56. comfyui_frontend_package/static/assets/WidgetLegacy-DxWXa1q8.js.map +1 -0
  57. comfyui_frontend_package/static/assets/WidgetMarkdown-BbdYbwjR.js +2 -0
  58. comfyui_frontend_package/static/assets/{WidgetMarkdown-voa7Ohgp.js.map → WidgetMarkdown-BbdYbwjR.js.map} +1 -1
  59. comfyui_frontend_package/static/assets/WidgetRecordAudio-DQzt1Okr.js +2 -0
  60. comfyui_frontend_package/static/assets/WidgetRecordAudio-DQzt1Okr.js.map +1 -0
  61. comfyui_frontend_package/static/assets/WidgetSelect-BCeT8JsM.js +2 -0
  62. comfyui_frontend_package/static/assets/WidgetSelect-BCeT8JsM.js.map +1 -0
  63. comfyui_frontend_package/static/assets/{WidgetSelect.vue_vue_type_script_setup_true_lang-CT0J0vij.js → WidgetSelect.vue_vue_type_script_setup_true_lang-DnNAGP6n.js} +2 -2
  64. comfyui_frontend_package/static/assets/{WidgetSelect.vue_vue_type_script_setup_true_lang-CT0J0vij.js.map → WidgetSelect.vue_vue_type_script_setup_true_lang-DnNAGP6n.js.map} +1 -1
  65. comfyui_frontend_package/static/assets/{WidgetTextarea-SHMM72Cj.js → WidgetTextarea-DtdgdYZv.js} +2 -2
  66. comfyui_frontend_package/static/assets/{WidgetTextarea-SHMM72Cj.js.map → WidgetTextarea-DtdgdYZv.js.map} +1 -1
  67. comfyui_frontend_package/static/assets/{WidgetToggleSwitch-BmT1MQCn.js → WidgetToggleSwitch-BZnc8nGp.js} +2 -2
  68. comfyui_frontend_package/static/assets/{WidgetToggleSwitch-BmT1MQCn.js.map → WidgetToggleSwitch-BZnc8nGp.js.map} +1 -1
  69. comfyui_frontend_package/static/assets/{WidgetWithControl.vue_vue_type_script_setup_true_lang-CTEGWC4h.js → WidgetWithControl.vue_vue_type_script_setup_true_lang-39lKeCWN.js} +3 -3
  70. comfyui_frontend_package/static/assets/{WidgetWithControl.vue_vue_type_script_setup_true_lang-CTEGWC4h.js.map → WidgetWithControl.vue_vue_type_script_setup_true_lang-39lKeCWN.js.map} +1 -1
  71. comfyui_frontend_package/static/assets/{audioService-BcbrJBnn.js → audioService-CxmGtl4K.js} +2 -2
  72. comfyui_frontend_package/static/assets/{audioService-BcbrJBnn.js.map → audioService-CxmGtl4K.js.map} +1 -1
  73. comfyui_frontend_package/static/assets/{audioUtils-CJCA0wCG.js → audioUtils-B4fAuqez.js} +2 -2
  74. comfyui_frontend_package/static/assets/{audioUtils-CJCA0wCG.js.map → audioUtils-B4fAuqez.js.map} +1 -1
  75. comfyui_frontend_package/static/assets/commands-DHxq3nWN.js +2 -0
  76. comfyui_frontend_package/static/assets/commands-DHxq3nWN.js.map +1 -0
  77. comfyui_frontend_package/static/assets/{index-kQCr6fgp.js → index-B7ehZHKU.js} +2 -2
  78. comfyui_frontend_package/static/assets/{index-kQCr6fgp.js.map → index-B7ehZHKU.js.map} +1 -1
  79. comfyui_frontend_package/static/assets/{index-DvCHS_f2.js → index-BFHZsBkN.js} +25 -25
  80. comfyui_frontend_package/static/assets/index-BFHZsBkN.js.map +1 -0
  81. comfyui_frontend_package/static/assets/index-DJa4hQi7.css +1 -0
  82. comfyui_frontend_package/static/assets/index-tImAQKwZ.js +5 -0
  83. comfyui_frontend_package/static/assets/index-tImAQKwZ.js.map +1 -0
  84. comfyui_frontend_package/static/assets/{keybindingService-D3pQ4cJG.js → keybindingService-B_cUhEnt.js} +2 -2
  85. comfyui_frontend_package/static/assets/{keybindingService-D3pQ4cJG.js.map → keybindingService-B_cUhEnt.js.map} +1 -1
  86. comfyui_frontend_package/static/assets/{main-BFC5CmrY.js → main-B3vd7GL1.js} +3 -3
  87. comfyui_frontend_package/static/assets/main-B3vd7GL1.js.map +1 -0
  88. comfyui_frontend_package/static/assets/{main-M4YqFlAB.js → main-BKCc2TkD.js} +3 -3
  89. comfyui_frontend_package/static/assets/main-BKCc2TkD.js.map +1 -0
  90. comfyui_frontend_package/static/assets/{main-C0iYASPd.js → main-BNvzUx74.js} +3 -3
  91. comfyui_frontend_package/static/assets/main-BNvzUx74.js.map +1 -0
  92. comfyui_frontend_package/static/assets/main-BPu7av80.js +17 -0
  93. comfyui_frontend_package/static/assets/main-BPu7av80.js.map +1 -0
  94. comfyui_frontend_package/static/assets/{main-Dd3BY3MO.js → main-BQ4z0Xxc.js} +2 -2
  95. comfyui_frontend_package/static/assets/main-BQ4z0Xxc.js.map +1 -0
  96. comfyui_frontend_package/static/assets/{main-BI-3llij.js → main-BoyaoV4J.js} +2 -2
  97. comfyui_frontend_package/static/assets/main-BoyaoV4J.js.map +1 -0
  98. comfyui_frontend_package/static/assets/{main-DB30B6rY.js → main-CJ1ZmTbz.js} +3 -3
  99. comfyui_frontend_package/static/assets/main-CJ1ZmTbz.js.map +1 -0
  100. comfyui_frontend_package/static/assets/{main-D8hMMX5u.js → main-DxByB8u3.js} +2 -2
  101. comfyui_frontend_package/static/assets/main-DxByB8u3.js.map +1 -0
  102. comfyui_frontend_package/static/assets/{main-BdVq5c-Q.js → main-Dyk43SJi.js} +2 -2
  103. comfyui_frontend_package/static/assets/main-Dyk43SJi.js.map +1 -0
  104. comfyui_frontend_package/static/assets/{main-Cte3FX_T.js → main-QMLeyFJQ.js} +3 -3
  105. comfyui_frontend_package/static/assets/main-QMLeyFJQ.js.map +1 -0
  106. comfyui_frontend_package/static/assets/{main-BPVbVwRz.js → main-f7MqrMkx.js} +3 -3
  107. comfyui_frontend_package/static/assets/main-f7MqrMkx.js.map +1 -0
  108. comfyui_frontend_package/static/assets/nodeDefs-CqPqVYqF.js +54 -0
  109. comfyui_frontend_package/static/assets/nodeDefs-CqPqVYqF.js.map +1 -0
  110. comfyui_frontend_package/static/assets/settings-BDcsAddA.js +6 -0
  111. comfyui_frontend_package/static/assets/settings-BDcsAddA.js.map +1 -0
  112. comfyui_frontend_package/static/assets/settings-BscQZApb.js +6 -0
  113. comfyui_frontend_package/static/assets/settings-BscQZApb.js.map +1 -0
  114. comfyui_frontend_package/static/assets/settings-BxGvSZQt.js +6 -0
  115. comfyui_frontend_package/static/assets/settings-BxGvSZQt.js.map +1 -0
  116. comfyui_frontend_package/static/assets/settings-CRbIyGOx.js +6 -0
  117. comfyui_frontend_package/static/assets/settings-CRbIyGOx.js.map +1 -0
  118. comfyui_frontend_package/static/assets/settings-C_M95LcR.js +6 -0
  119. comfyui_frontend_package/static/assets/settings-C_M95LcR.js.map +1 -0
  120. comfyui_frontend_package/static/assets/{settings-C83z84hb.js → settings-CfAtcjYG.js} +3 -3
  121. comfyui_frontend_package/static/assets/settings-CfAtcjYG.js.map +1 -0
  122. comfyui_frontend_package/static/assets/settings-D1FGfDLO.js +6 -0
  123. comfyui_frontend_package/static/assets/settings-D1FGfDLO.js.map +1 -0
  124. comfyui_frontend_package/static/assets/settings-DIhoSYUg.js +6 -0
  125. comfyui_frontend_package/static/assets/settings-DIhoSYUg.js.map +1 -0
  126. comfyui_frontend_package/static/assets/settings-DR935Ify.js +6 -0
  127. comfyui_frontend_package/static/assets/settings-DR935Ify.js.map +1 -0
  128. comfyui_frontend_package/static/assets/settings-DwzAhg99.js +6 -0
  129. comfyui_frontend_package/static/assets/settings-DwzAhg99.js.map +1 -0
  130. comfyui_frontend_package/static/assets/settings-ydiuzS6H.js +6 -0
  131. comfyui_frontend_package/static/assets/settings-ydiuzS6H.js.map +1 -0
  132. comfyui_frontend_package/static/assets/{vendor-primevue-Bp7MMXLP.js → vendor-primevue-DeKsC2uk.js} +2 -2
  133. comfyui_frontend_package/static/assets/{vendor-primevue-Bp7MMXLP.js.map → vendor-primevue-DeKsC2uk.js.map} +1 -1
  134. comfyui_frontend_package/static/index.html +1 -1
  135. {comfyui_frontend_package-1.37.9.dist-info → comfyui_frontend_package-1.37.11.dist-info}/METADATA +1 -1
  136. {comfyui_frontend_package-1.37.9.dist-info → comfyui_frontend_package-1.37.11.dist-info}/RECORD +138 -130
  137. comfyui_frontend_package/static/assets/GraphView-BZLpyVMl.css +0 -1
  138. comfyui_frontend_package/static/assets/GraphView-C35zkdNN.js +0 -15
  139. comfyui_frontend_package/static/assets/GraphView-C35zkdNN.js.map +0 -1
  140. comfyui_frontend_package/static/assets/LazyImage.vue_vue_type_script_setup_true_lang-C58MdJKR.js +0 -2
  141. comfyui_frontend_package/static/assets/LazyImage.vue_vue_type_script_setup_true_lang-C58MdJKR.js.map +0 -1
  142. comfyui_frontend_package/static/assets/Load3D-BAJ3yM4D.js.map +0 -1
  143. comfyui_frontend_package/static/assets/SubscriptionRequiredDialogContent-BJ80blC4.css +0 -1
  144. comfyui_frontend_package/static/assets/SubscriptionRequiredDialogContent-CDaF1jns.js +0 -2
  145. comfyui_frontend_package/static/assets/WidgetInputNumber-Cnhf4Ann.js +0 -2
  146. comfyui_frontend_package/static/assets/WidgetInputNumber-Cnhf4Ann.js.map +0 -1
  147. comfyui_frontend_package/static/assets/WidgetLegacy-AkIJRd8v.js +0 -2
  148. comfyui_frontend_package/static/assets/WidgetLegacy-AkIJRd8v.js.map +0 -1
  149. comfyui_frontend_package/static/assets/WidgetMarkdown-voa7Ohgp.js +0 -2
  150. comfyui_frontend_package/static/assets/WidgetRecordAudio-DelweXYm.js +0 -2
  151. comfyui_frontend_package/static/assets/WidgetRecordAudio-DelweXYm.js.map +0 -1
  152. comfyui_frontend_package/static/assets/WidgetSelect-XG4R8CnZ.js +0 -2
  153. comfyui_frontend_package/static/assets/WidgetSelect-XG4R8CnZ.js.map +0 -1
  154. comfyui_frontend_package/static/assets/index-BB_8e12C.css +0 -1
  155. comfyui_frontend_package/static/assets/index-Cm0D-ExL.js +0 -5
  156. comfyui_frontend_package/static/assets/index-Cm0D-ExL.js.map +0 -1
  157. comfyui_frontend_package/static/assets/index-DvCHS_f2.js.map +0 -1
  158. comfyui_frontend_package/static/assets/main-BFC5CmrY.js.map +0 -1
  159. comfyui_frontend_package/static/assets/main-BI-3llij.js.map +0 -1
  160. comfyui_frontend_package/static/assets/main-BPVbVwRz.js.map +0 -1
  161. comfyui_frontend_package/static/assets/main-BdVq5c-Q.js.map +0 -1
  162. comfyui_frontend_package/static/assets/main-C0iYASPd.js.map +0 -1
  163. comfyui_frontend_package/static/assets/main-Cte3FX_T.js.map +0 -1
  164. comfyui_frontend_package/static/assets/main-D8hMMX5u.js.map +0 -1
  165. comfyui_frontend_package/static/assets/main-DB30B6rY.js.map +0 -1
  166. comfyui_frontend_package/static/assets/main-Dd3BY3MO.js.map +0 -1
  167. comfyui_frontend_package/static/assets/main-M4YqFlAB.js.map +0 -1
  168. comfyui_frontend_package/static/assets/settings-2GCqRrJG.js +0 -6
  169. comfyui_frontend_package/static/assets/settings-2GCqRrJG.js.map +0 -1
  170. comfyui_frontend_package/static/assets/settings-BwT6YspU.js +0 -6
  171. comfyui_frontend_package/static/assets/settings-BwT6YspU.js.map +0 -1
  172. comfyui_frontend_package/static/assets/settings-C83z84hb.js.map +0 -1
  173. comfyui_frontend_package/static/assets/settings-CpGAolL8.js +0 -6
  174. comfyui_frontend_package/static/assets/settings-CpGAolL8.js.map +0 -1
  175. comfyui_frontend_package/static/assets/settings-DHYEklkf.js +0 -6
  176. comfyui_frontend_package/static/assets/settings-DHYEklkf.js.map +0 -1
  177. comfyui_frontend_package/static/assets/settings-DLFPCNJr.js +0 -6
  178. comfyui_frontend_package/static/assets/settings-DLFPCNJr.js.map +0 -1
  179. comfyui_frontend_package/static/assets/settings-JVJwzdtf.js +0 -6
  180. comfyui_frontend_package/static/assets/settings-JVJwzdtf.js.map +0 -1
  181. comfyui_frontend_package/static/assets/settings-Tg5NBf0t.js +0 -6
  182. comfyui_frontend_package/static/assets/settings-Tg5NBf0t.js.map +0 -1
  183. comfyui_frontend_package/static/assets/settings-_tes1LYa.js +0 -6
  184. comfyui_frontend_package/static/assets/settings-_tes1LYa.js.map +0 -1
  185. comfyui_frontend_package/static/assets/settings-cav_bQJj.js +0 -6
  186. comfyui_frontend_package/static/assets/settings-cav_bQJj.js.map +0 -1
  187. {comfyui_frontend_package-1.37.9.dist-info → comfyui_frontend_package-1.37.11.dist-info}/WHEEL +0 -0
  188. {comfyui_frontend_package-1.37.9.dist-info → comfyui_frontend_package-1.37.11.dist-info}/top_level.txt +0 -0
@@ -0,0 +1 @@
1
+ [data-v-78b7f6de] .p-splitter-gutter{pointer-events:auto}[data-v-78b7f6de] .p-splitter-gutter:hover,[data-v-78b7f6de] .p-splitter-gutter[data-p-gutter-resizing=true]{transition:background-color .2s ease .3s;background-color:var(--p-primary-color)}[data-v-78b7f6de] .side-bar-panel[style*="display: none"]+.p-splitter-gutter,[data-v-78b7f6de] .p-splitter-gutter+.side-bar-panel[style*="display: none"]{display:none}.splitter-overlay-bottom[data-v-78b7f6de] .p-splitter-gutter{transform:translateY(5px)}.p-breadcrumb-item-link[data-v-d7b126c3],.p-breadcrumb-item-icon[data-v-d7b126c3]{-webkit-user-select:none;user-select:none}.p-breadcrumb-item-link[data-v-d7b126c3]{overflow:hidden}.p-breadcrumb-item-label[data-v-d7b126c3]{text-overflow:ellipsis;white-space:nowrap;overflow:hidden}.active-breadcrumb-item[data-v-d7b126c3]{color:var(--text-primary)}.subgraph-breadcrumb[data-v-50f75d4e]:not(:empty){flex:1 10000 auto;min-width:120px}:is(.subgraph-breadcrumb[data-v-50f75d4e],[data-v-50f75d4e] .p-breadcrumb){overflow:hidden}[data-v-50f75d4e] .p-breadcrumb{background-color:#0000;width:100%}[data-v-50f75d4e] .p-breadcrumb-item{height:calc(var(--spacing,.25rem)*8);min-width:calc(var(--p-breadcrumb-item-min-width) + 1rem);background-color:#0000;border:1px solid #0000;flex-shrink:10000;align-items:center;transition:all .2s;display:flex;overflow:hidden}[data-v-50f75d4e] .p-breadcrumb-separator{padding:0 var(--p-breadcrumb-item-margin);background-color:#0000;border:1px solid #0000;display:flex}[data-v-50f75d4e] .p-breadcrumb-item-link{padding:0 calc(var(--p-breadcrumb-item-margin) + var(--p-breadcrumb-item-padding))}[data-v-50f75d4e] .p-breadcrumb-item:hover{border-radius:var(--radius-lg,.5rem);border-color:var(--interface-stroke);background-color:var(--comfy-menu-bg)}[data-v-50f75d4e] .p-breadcrumb-item:has(.p-breadcrumb-item-link-icon-visible){min-width:calc(var(--p-breadcrumb-item-min-width) + 1rem + 20px)}[data-v-50f75d4e] .p-breadcrumb-item:first-child{flex-shrink:5000}[data-v-50f75d4e] .p-breadcrumb-item:first-child .p-breadcrumb-item-link{padding-left:var(--p-breadcrumb-item-padding)}[data-v-50f75d4e] .p-breadcrumb-item:last-child{flex-shrink:1}[data-v-50f75d4e] .p-breadcrumb-item-link-menu-visible{background-color:var(--fg-color)!important}@supports (color:color-mix(in lab,red,red)){[data-v-50f75d4e] .p-breadcrumb-item-link-menu-visible{background-color:color-mix(in srgb,var(--fg-color)10%,var(--comfy-menu-bg))!important}}[data-v-50f75d4e] .p-breadcrumb-item-link-menu-visible{color:var(--fg-color)}.subgraph-breadcrumb-collapse .p-breadcrumb-list .p-breadcrumb-item,.subgraph-breadcrumb-collapse .p-breadcrumb-list .p-breadcrumb-separator{display:none}.subgraph-breadcrumb-collapse .p-breadcrumb-list .p-breadcrumb-item:nth-last-child(3),.subgraph-breadcrumb-collapse .p-breadcrumb-list .p-breadcrumb-separator:nth-last-child(2),.subgraph-breadcrumb-collapse .p-breadcrumb-list .p-breadcrumb-item:last-child{display:flex}[data-v-9d1ea2c9] .p-tablist-active-bar{display:none}.dom-widget[data-v-781496d2]>*{width:100%;height:100%}.zoomInputContainer:focus-within{border:1px solid var(--color-white)}.node-tooltip[data-v-96b1458a]{pointer-events:none;background:var(--comfy-input-bg);border-radius:5px;box-shadow:0 0 5px #0006;color:var(--input-text);left:0;max-width:30vw;padding:4px 8px;position:absolute;top:0;transform:translate(5px,calc(-100% - 5px));white-space:pre-wrap;z-index:99999}.color-picker-container[data-v-2197e0a1]{transform:translate(-50%)}[data-v-2197e0a1] .p-togglebutton{padding-inline:calc(var(--spacing,.25rem)*1);padding-block:calc(var(--spacing,.25rem)*2)}.selection-toolbox[data-v-c6489a20]{transform:translate(-50%) translateY(-120%)}@keyframes slideUp-c6489a20{0%{transform:translate(-50%) translateY(-100%);opacity:0}50%{transform:translate(-50%) translateY(-125%);opacity:.5}to{transform:translate(-50%) translateY(-120%);opacity:1}}.slide-up-enter-active[data-v-c6489a20]{animation:slideUp-c6489a20 125ms ease-out}.slide-up-leave-active[data-v-c6489a20]{animation:slideUp-c6489a20 25ms ease-out reverse}.group-title-editor.node-title-editor[data-v-aceb018c]{z-index:9999;padding:.25rem}[data-v-aceb018c] .editable-text{width:100%;height:100%}[data-v-aceb018c] .editable-text input{width:100%;height:100%;font-size:inherit}[data-v-acda36a0] .highlight{background-color:var(--p-primary-color);color:var(--p-primary-contrast-color);font-weight:700;border-radius:.25rem;padding:0 .125rem;margin:-.125rem .125rem}.invisible-dialog-root{width:60%;min-width:24rem;max-width:48rem;border:0!important;background-color:transparent!important;margin-top:25vh;margin-left:400px}@media all and (max-width:768px){.invisible-dialog-root{margin-left:0}}.node-search-box-dialog-mask{align-items:flex-start!important}.release-toast-popup[data-v-ba02c61a]{position:absolute;bottom:1rem;z-index:1000;pointer-events:auto}.release-toast-popup.sidebar-left[data-v-ba02c61a],.release-toast-popup.sidebar-left.small-sidebar[data-v-ba02c61a]{left:1rem}.release-toast-popup.sidebar-right[data-v-ba02c61a]{right:1rem}.whats-new-popup-container[data-v-98a9f324]{--whats-new-popup-bottom: 1rem;position:absolute;bottom:var(--whats-new-popup-bottom);z-index:1000;pointer-events:auto}.whats-new-popup[data-v-98a9f324]{background:var(--interface-menu-surface);border-radius:8px;max-width:400px;width:400px;border:1px solid var(--interface-menu-stroke);box-shadow:1px 1px 8px #0003;position:relative;display:flex;flex-direction:column}.modal-body[data-v-98a9f324]{display:flex;flex-direction:column;gap:1rem;padding:0;flex:1}.modal-header[data-v-98a9f324]{display:flex;flex-direction:column;gap:8px}.content-text[data-v-98a9f324]{color:var(--text-primary);font-size:14px;line-height:1.5;word-wrap:break-word;padding:0 1rem}.content-text[data-v-98a9f324] *{box-sizing:border-box}.content-text[data-v-98a9f324] h1{color:var(--text-secondary);font-family:Inter,sans-serif;font-size:14px;font-weight:400;margin-top:1rem;margin-bottom:8px;text-transform:uppercase;letter-spacing:.05em}.content-text[data-v-98a9f324] h2,.content-text[data-v-98a9f324] h1+p strong{color:var(--text-primary);font-family:Inter,sans-serif;font-size:14px;font-weight:600;margin:0 0 8px;line-height:1.429}.content-text[data-v-98a9f324] p{color:var(--text-secondary);font-family:Inter,sans-serif;margin:1rem 0}.content-text[data-v-98a9f324] ul,.content-text[data-v-98a9f324] ol{margin-bottom:0;padding-left:0;list-style:none}.content-text[data-v-98a9f324] ul:first-child,.content-text[data-v-98a9f324] ol:first-child{margin-top:0}.content-text[data-v-98a9f324] ul:last-child,.content-text[data-v-98a9f324] ol:last-child{margin-bottom:0}.content-text[data-v-98a9f324] li{margin-bottom:6px;position:relative;padding-left:18px;color:var(--text-secondary);font-family:Inter,sans-serif;font-size:14px;font-weight:400;line-height:1.2102}.content-text[data-v-98a9f324] li:last-child{margin-bottom:0}.content-text[data-v-98a9f324] li:before{content:"";position:absolute;left:4px;top:7px;width:6px;height:6px;border:2px solid var(--text-secondary);border-radius:50%;background:transparent}.content-text[data-v-98a9f324] li strong{color:var(--text-secondary);font-family:Inter,sans-serif;font-size:14px;font-weight:400;line-height:1.2102;margin-right:4px}.content-text[data-v-98a9f324] li p{margin:2px 0 0;display:inline}.content-text[data-v-98a9f324] code{background-color:var(--input-surface);border:1px solid var(--interface-menu-stroke);border-radius:4px;padding:2px 6px;color:var(--text-primary);white-space:nowrap}.content-text[data-v-98a9f324] img{width:100%;height:200px;margin:0 0 16px;object-fit:cover;display:block;border-radius:8px}.content-text[data-v-98a9f324] img:first-child{margin:-1rem -1rem 16px;width:calc(100% + 2rem);border-radius:8px 8px 0 0}.content-text[data-v-98a9f324]:has(img:first-child){border-left:1px solid var(--interface-menu-stroke);border-right:1px solid var(--interface-menu-stroke);border-top:1px solid var(--interface-menu-stroke);border-bottom-left-radius:8px;border-bottom-right-radius:8px;margin:-1px -1px 0}.content-text[data-v-98a9f324] img+h1{margin-top:0}.content-text[data-v-98a9f324] h3{color:var(--text-primary);font-family:Inter,sans-serif;font-size:16px;font-weight:600;margin:16px 0 8px;line-height:1.4}.modal-footer[data-v-98a9f324]{display:flex;justify-content:space-between;align-items:center;gap:16px;padding:16px;border-top:none}.footer-actions[data-v-98a9f324]{display:flex;align-items:center;gap:16px}.learn-more-link[data-v-98a9f324]{display:flex;align-items:center;gap:8px;color:var(--text-secondary);font-size:14px;font-weight:400;line-height:1.2102;text-decoration:none;padding:4px 0}.learn-more-link[data-v-98a9f324]:hover{color:var(--text-primary)}.learn-more-link i[data-v-98a9f324]{width:16px;height:16px}.action-secondary[data-v-98a9f324]{height:32px;padding:4px 0;background:transparent;border:none;color:var(--text-secondary);font-size:14px;font-weight:400;line-height:1.2102;cursor:pointer;border-radius:4px}.action-secondary[data-v-98a9f324]:hover{color:var(--text-primary)}.action-primary[data-v-98a9f324]{height:40px;padding:8px 16px;background:var(--interface-menu-component-surface-hovered);border-radius:8px;border:none;color:var(--text-primary);font-size:14px;font-weight:400;line-height:1.2102;cursor:pointer}.action-primary[data-v-98a9f324]:hover{background:var(--button-hover-surface)}.help-center-menu[data-v-8ecd06e2]{width:256px;max-height:500px;overflow-y:auto;background:var(--interface-menu-surface);border-radius:8px;box-shadow:0 2px 12px #0000001a;border:1px solid var(--interface-menu-stroke);padding:12px 8px;position:relative}.help-menu-item[data-v-8ecd06e2]{display:flex;align-items:center;width:100%;height:32px;min-height:24px;padding:8px;gap:8px;background:transparent;border:none;border-radius:4px;cursor:pointer;transition:background-color .2s;font-size:.9rem;color:var(--text-primary);text-align:left}.help-menu-item[data-v-8ecd06e2]:hover{background-color:var(--interface-menu-component-surface-hovered)}.help-menu-item[data-v-8ecd06e2]:focus,.help-menu-item[data-v-8ecd06e2]:focus-visible{outline:none;box-shadow:none}.help-menu-icon-container[data-v-8ecd06e2]{position:relative;width:16px;height:16px;flex-shrink:0}.help-menu-icon[data-v-8ecd06e2]{width:16px;height:16px;font-size:16px;color:var(--text-primary);display:flex;justify-content:center;align-items:center;flex-shrink:0}.help-menu-icon svg[data-v-8ecd06e2]{width:16px;height:16px;color:var(--text-primary)}.menu-red-dot[data-v-8ecd06e2]{position:absolute;top:-2px;right:-2px;width:8px;height:8px;background:#ff3b30;border-radius:50%;border:1.5px solid var(--p-content-background);z-index:1}.menu-label[data-v-8ecd06e2]{flex:1}.more-item[data-v-8ecd06e2]{justify-content:space-between}.section-description[data-v-8ecd06e2]{color:var(--text-secondary);font-family:var(--font-inter);font-size:12px;font-style:normal;font-weight:700;line-height:normal;margin:0;text-transform:uppercase;letter-spacing:.5px}.release-menu-item[data-v-8ecd06e2]{position:relative}.release-content[data-v-8ecd06e2]{flex:1;display:flex;flex-direction:column;gap:4px;min-width:0}.release-title[data-v-8ecd06e2]{font-size:.9rem;line-height:1.2;font-weight:500;color:var(--text-primary)}.release-date[data-v-8ecd06e2]{height:16px;color:var(--text-secondary);font-family:var(--font-inter);font-size:12px;font-style:normal;font-weight:400;line-height:normal;overflow:hidden;text-overflow:ellipsis;display:-webkit-box;-webkit-line-clamp:1;-webkit-box-orient:vertical}.release-date .hover-state[data-v-8ecd06e2]{display:none}.release-menu-item:hover .release-date .normal-state[data-v-8ecd06e2],.release-menu-item:focus-within .release-date .normal-state[data-v-8ecd06e2]{display:none}.release-menu-item:hover .release-date .hover-state[data-v-8ecd06e2],.release-menu-item:focus-within .release-date .hover-state[data-v-8ecd06e2]{display:inline}.more-submenu[data-v-8ecd06e2]{width:210px;padding:12px 8px;background:var(--interface-menu-surface);border-radius:8px;border:1px solid var(--interface-menu-stroke);box-shadow:0 2px 12px #0000001a;overflow:hidden;transition:opacity .15s ease-out}.submenu-item[data-v-8ecd06e2]{padding:8px;height:32px;min-height:24px;border-radius:4px;color:var(--text-primary);font-size:.9rem;font-weight:inherit;line-height:inherit}.submenu-item[data-v-8ecd06e2]:hover{background-color:var(--interface-menu-component-surface-hovered)}.submenu-item[data-v-8ecd06e2]:focus,.submenu-item[data-v-8ecd06e2]:focus-visible{outline:none;box-shadow:none}.submenu-divider[data-v-8ecd06e2]{height:1px;background:var(--interface-menu-stroke);margin:4px 0}.help-center-menu[data-v-8ecd06e2]::-webkit-scrollbar{width:6px}.help-center-menu[data-v-8ecd06e2]::-webkit-scrollbar-track{background:transparent}.help-center-menu[data-v-8ecd06e2]::-webkit-scrollbar-thumb{background:var(--interface-menu-stroke);border-radius:3px}.help-center-menu[data-v-8ecd06e2]::-webkit-scrollbar-thumb:hover{background:var(--text-secondary)}@media(prefers-reduced-motion:reduce){.help-menu-item[data-v-8ecd06e2]{transition:none}}.help-center-backdrop[data-v-2583d84f]{position:absolute;inset:0;z-index:9999;background:transparent}.help-center-popup[data-v-2583d84f]{position:absolute;bottom:1rem;z-index:10000;animation:slideInUp-2583d84f .2s ease-out;pointer-events:auto}.help-center-popup.sidebar-left[data-v-2583d84f],.help-center-popup.sidebar-left.small-sidebar[data-v-2583d84f]{left:1rem}.help-center-popup.sidebar-right[data-v-2583d84f]{right:1rem}.help-center-popup.topbar-right[data-v-2583d84f]{top:2rem;right:1rem;bottom:auto;animation:slideInDown-2583d84f .2s ease-out}@keyframes slideInDown-2583d84f{0%{opacity:0;transform:translateY(-20px)}to{opacity:1;transform:translateY(0)}}@keyframes slideInUp-2583d84f{0%{opacity:0;transform:translateY(20px)}to{opacity:1;transform:translateY(0)}}img[data-v-c216f2c0]{transition:transform 1s cubic-bezier(.2,0,.4,1)}.workflow-template-selector-dialog.base-widget-layout{width:100%!important;max-width:1400px;height:100%!important;aspect-ratio:auto!important}@media(min-width:1600px){.workflow-template-selector-dialog.base-widget-layout{max-width:1600px}}.comfy-menu-button-wrapper[data-v-7f8c3b49]{width:var(--sidebar-width);height:var(--sidebar-item-height)}.comfy-menu-button-wrapper[data-v-7f8c3b49]:hover{background:var(--interface-panel-hover-surface)}.comfy-menu-button-active[data-v-7f8c3b49],.comfy-menu-button-active[data-v-7f8c3b49]:hover{background:var(--interface-panel-selected-surface)}.keybinding-tag[data-v-7f8c3b49]{background:var(--p-content-hover-background);border-color:var(--p-content-border-color);border-style:solid}.comfy-command-menu{--p-tieredmenu-item-focus-background: color-mix( in srgb, var(--fg-color) 15%, transparent );--p-tieredmenu-item-active-background: color-mix( in srgb, var(--fg-color) 10%, transparent )}.comfy-command-menu ul{background-color:var(--comfy-menu-bg)!important}.side-bar-button-icon{font-size:var(--sidebar-icon-size)!important}.side-bar-button-selected{background-color:var(--interface-panel-selected-surface);color:var(--content-hover-fg)}.side-bar-button:hover{background-color:var(--interface-panel-hover-surface);color:var(--content-hover-fg)}.side-bar-button-selected .side-bar-button-icon{font-size:var(--sidebar-icon-size)!important}.side-bar-button[data-v-bbb98ec9]{width:var(--sidebar-width);height:var(--sidebar-item-height);border-radius:0;flex-shrink:0}.side-tool-bar-end .side-bar-button[data-v-bbb98ec9]{height:var(--sidebar-width)}.side-bar-button-content[data-v-bbb98ec9]{align-items:center;gap:calc(var(--spacing,.25rem)*2);flex-direction:column;display:flex}.side-bar-button-label[data-v-bbb98ec9]{text-align:center;font-size:10px;line-height:1}.comfyui-body-left .side-bar-button.side-bar-button-selected[data-v-bbb98ec9],.comfyui-body-left .side-bar-button.side-bar-button-selected[data-v-bbb98ec9]:hover{border-left:4px solid var(--p-button-text-primary-color)}.comfyui-body-right .side-bar-button.side-bar-button-selected[data-v-bbb98ec9],.comfyui-body-right .side-bar-button.side-bar-button-selected[data-v-bbb98ec9]:hover{border-right:4px solid var(--p-button-text-primary-color)}[data-v-4a7593e2] .p-badge{background:#ff3b30;color:#ff3b30;min-width:8px;height:8px;padding:0;border-radius:9999px;font-size:0;margin-top:4px;margin-right:4px;border:none;outline:none;box-shadow:none}[data-v-4a7593e2] .p-badge.p-badge-dot{width:8px!important}:root{--sidebar-padding: 4px;--sidebar-icon-size: 1rem;--sidebar-default-floating-width: 48px;--sidebar-default-connected-width: calc( var(--sidebar-default-floating-width) + var(--sidebar-padding) * 2 );--sidebar-default-item-height: 56px;--sidebar-small-floating-width: 48px;--sidebar-small-connected-width: calc( var(--sidebar-small-floating-width) + var(--sidebar-padding) * 2 );--sidebar-small-item-height: 48px;--sidebar-width: var(--sidebar-default-floating-width);--sidebar-item-height: var(--sidebar-default-item-height)}:root:has(.side-tool-bar-container.small-sidebar){--sidebar-width: var(--sidebar-small-floating-width);--sidebar-item-height: var(--sidebar-small-item-height)}:root:has(.side-tool-bar-container.connected-sidebar){--sidebar-width: var(--sidebar-default-connected-width)}:root:has(.side-tool-bar-container.small-sidebar.connected-sidebar){--sidebar-width: var(--sidebar-small-connected-width)}.floating-sidebar[data-v-9d98575c]{padding:var(--sidebar-padding)}.floating-sidebar .sidebar-item-group[data-v-9d98575c]{border-color:var(--p-panel-border-color)}.connected-sidebar[data-v-9d98575c]{padding:var(--sidebar-padding)0;background-color:var(--comfy-menu-bg)}.sidebar-item-group[data-v-9d98575c]{background-color:var(--comfy-menu-bg);border:1px solid #0000}.overflowing-sidebar[data-v-9d98575c] .comfy-menu-button-wrapper{z-index:1;background-color:var(--comfy-menu-bg);position:sticky;top:0}@layer properties{@supports (((-webkit-hyphens:none)) and (not (margin-trim:inline))) or ((-moz-orient:inline) and (not (color:rgb(from red r g b)))){[data-v-4c13cb50],[data-v-4c13cb50]:before,[data-v-4c13cb50]:after,[data-v-4c13cb50]::backdrop{--tw-shadow:0 0 #0000;--tw-shadow-color:initial;--tw-shadow-alpha:100%;--tw-inset-shadow:0 0 #0000;--tw-inset-shadow-color:initial;--tw-inset-shadow-alpha:100%;--tw-ring-color:initial;--tw-ring-shadow:0 0 #0000;--tw-inset-ring-color:initial;--tw-inset-ring-shadow:0 0 #0000;--tw-ring-inset:initial;--tw-ring-offset-width:0px;--tw-ring-offset-color:#fff;--tw-ring-offset-shadow:0 0 #0000;--tw-font-weight:initial}}}.workflow-preview-content[data-v-4c13cb50]{border-radius:var(--radius-xl,.75rem);max-width:var(--popover-width);background-color:var(--comfy-menu-bg);color:var(--fg-color);flex-direction:column;display:flex;overflow:hidden}.workflow-preview-thumbnail[data-v-4c13cb50]{padding:calc(var(--spacing,.25rem)*2);position:relative}.workflow-preview-thumbnail img[data-v-4c13cb50]{--tw-shadow:0 4px 6px -1px var(--tw-shadow-color,#0000001a),0 2px 4px -2px var(--tw-shadow-color,#0000001a);box-shadow:var(--tw-inset-shadow),var(--tw-inset-ring-shadow),var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow);background-color:var(--comfy-menu-bg)}@supports (color:color-mix(in lab,red,red)){.workflow-preview-thumbnail img[data-v-4c13cb50]{background-color:color-mix(in srgb,var(--comfy-menu-bg)70%,black)}}.dark-theme .workflow-preview-thumbnail img[data-v-4c13cb50]{--tw-shadow:0 10px 15px -3px var(--tw-shadow-color,#0000001a),0 4px 6px -4px var(--tw-shadow-color,#0000001a);box-shadow:var(--tw-inset-shadow),var(--tw-inset-ring-shadow),var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow)}.workflow-preview-footer[data-v-4c13cb50]{padding-inline:calc(var(--spacing,.25rem)*3);padding-top:calc(var(--spacing,.25rem)*1);padding-bottom:calc(var(--spacing,.25rem)*2)}.workflow-preview-name[data-v-4c13cb50]{font-size:var(--text-sm,.875rem);line-height:var(--tw-leading,var(--text-sm--line-height,calc(1.25/.875)));--tw-font-weight:var(--font-weight-medium,500);font-weight:var(--font-weight-medium,500);text-overflow:ellipsis;white-space:nowrap;color:var(--fg-color);display:block;overflow:hidden}@property --tw-font-weight{syntax:"*";inherits:false}@layer properties{@supports (((-webkit-hyphens:none)) and (not (margin-trim:inline))) or ((-moz-orient:inline) and (not (color:rgb(from red r g b)))){*,:before,:after,::backdrop{--tw-shadow:0 0 #0000;--tw-shadow-color:initial;--tw-shadow-alpha:100%;--tw-inset-shadow:0 0 #0000;--tw-inset-shadow-color:initial;--tw-inset-shadow-alpha:100%;--tw-ring-color:initial;--tw-ring-shadow:0 0 #0000;--tw-inset-ring-color:initial;--tw-inset-ring-shadow:0 0 #0000;--tw-ring-inset:initial;--tw-ring-offset-width:0px;--tw-ring-offset-color:#fff;--tw-ring-offset-shadow:0 0 #0000;--tw-translate-x:0;--tw-translate-y:0;--tw-translate-z:0}}}.workflow-popover-fade{--p-popover-background:transparent;--p-popover-content-padding:0;border-radius:var(--radius-xl,.75rem);--tw-shadow:0 10px 15px -3px var(--tw-shadow-color,#0000001a),0 4px 6px -4px var(--tw-shadow-color,#0000001a);box-shadow:var(--tw-inset-shadow),var(--tw-inset-ring-shadow),var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow);background-color:#0000;transition:opacity .15s ease-out!important}.workflow-popover-fade.p-popover-flipped{--tw-translate-y:-100%;translate:var(--tw-translate-x)var(--tw-translate-y)}.dark-theme .workflow-popover-fade{--tw-shadow:0 25px 50px -12px var(--tw-shadow-color,#00000040);box-shadow:var(--tw-inset-shadow),var(--tw-inset-ring-shadow),var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow)}.workflow-popover-fade.p-popover:after,.workflow-popover-fade.p-popover:before{--p-popover-border-color:var(--comfy-menu-secondary-bg);transform:translate(calc(-50% + var(--shift)));margin-left:0;left:50%}@property --tw-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-shadow-color{syntax:"*";inherits:false}@property --tw-shadow-alpha{syntax:"<percentage>";inherits:false;initial-value:100%}@property --tw-inset-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-inset-shadow-color{syntax:"*";inherits:false}@property --tw-inset-shadow-alpha{syntax:"<percentage>";inherits:false;initial-value:100%}@property --tw-ring-color{syntax:"*";inherits:false}@property --tw-ring-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-inset-ring-color{syntax:"*";inherits:false}@property --tw-inset-ring-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-ring-inset{syntax:"*";inherits:false}@property --tw-ring-offset-width{syntax:"<length>";inherits:false;initial-value:0}@property --tw-ring-offset-color{syntax:"*";inherits:false;initial-value:#fff}@property --tw-ring-offset-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-translate-x{syntax:"*";inherits:false;initial-value:0}@property --tw-translate-y{syntax:"*";inherits:false;initial-value:0}@property --tw-translate-z{syntax:"*";inherits:false;initial-value:0}.p-tooltip.workflow-tab-tooltip{z-index:1200!important}@layer properties{@supports (((-webkit-hyphens:none)) and (not (margin-trim:inline))) or ((-moz-orient:inline) and (not (color:rgb(from red r g b)))){[data-v-09158161],[data-v-09158161]:before,[data-v-09158161]:after,[data-v-09158161]::backdrop{--tw-border-style:solid}}}.workflow-tabs-container[data-v-09158161]{background-color:var(--comfy-menu-bg)}[data-v-09158161] .p-togglebutton{border-style:var(--tw-border-style);border-width:0;border-right-style:var(--tw-border-style);--tw-border-style:solid;padding:calc(var(--spacing,.25rem)*0);border-style:solid;border-right-width:1px;border-right-color:var(--border-color);background-color:#0000;border-radius:0;flex-shrink:1;min-width:90px;position:relative}.overflow-arrow[data-v-09158161]{padding-inline:calc(var(--spacing,.25rem)*2);border-radius:0}.overflow-arrow[disabled][data-v-09158161]{opacity:.25}[data-v-09158161] .p-togglebutton>.p-togglebutton-content{max-width:100%}[data-v-09158161] .workflow-tab{max-width:100%}[data-v-09158161] .p-togglebutton:before{display:none}[data-v-09158161] .p-togglebutton:first-child{border-left-style:var(--tw-border-style);--tw-border-style:solid;border-style:solid;border-left-width:1px;border-left-color:var(--border-color)}[data-v-09158161] .p-togglebutton:not(:first-child){border-left-style:var(--tw-border-style);border-left-width:0}[data-v-09158161] .p-togglebutton.p-togglebutton-checked{border-bottom-style:var(--tw-border-style);--tw-border-style:solid;border-style:solid;border-bottom-width:1px;border-bottom-color:var(--p-button-text-primary-color);height:100%}[data-v-09158161] .p-togglebutton:not(.p-togglebutton-checked){opacity:.75}:is([data-v-09158161] .p-togglebutton-checked .close-button,[data-v-09158161] .p-togglebutton:hover .close-button){visibility:visible}[data-v-09158161] .p-scrollpanel-content{height:100%}[data-v-09158161] .workflow-tabs{display:flex}:is([data-v-09158161] .p-scrollpanel:hover .p-scrollpanel-bar,[data-v-09158161] .p-scrollpanel:active .p-scrollpanel-bar){opacity:.5}[data-v-09158161] .p-selectbutton{border-radius:0;height:100%}.workflow-tabs-container-desktop[data-v-09158161]{max-width:env(titlebar-area-width,100vw)}.window-actions-spacer[data-v-09158161]{--window-actions-spacer-width:min(75px,env(titlebar-area-width,0)*9999);min-width:var(--window-actions-spacer-width);flex:auto}@property --tw-border-style{syntax:"*";inherits:false;initial-value:solid}.transform-pane--interacting[data-v-4d46eee6]{will-change:transform}.litegraph-minimap[data-v-66f11255]{overflow:hidden}.minimap-canvas[data-v-66f11255]{display:block;width:100%;height:100%;pointer-events:none}.minimap-viewport[data-v-66f11255]{position:absolute;top:0;left:0;pointer-events:none}.comfyui-body[data-v-5229bbd8]{grid-template-columns:auto 1fr auto;grid-template-rows:auto 1fr auto}.comfyui-body-top[data-v-5229bbd8]{order:-5;grid-column:1/-1;grid-row:1;z-index:1001;display:flex;flex-direction:column}.comfyui-body-left[data-v-5229bbd8]{order:-4;grid-column:1;grid-row:2;z-index:10;display:flex}.graph-canvas-container[data-v-5229bbd8]{width:100%;height:100%;order:-3;grid-column:2;grid-row:2;position:relative;overflow:clip}.comfyui-body-right[data-v-5229bbd8]{order:-2;z-index:10;grid-column:3;grid-row:2}.comfyui-body-bottom[data-v-5229bbd8]{order:4;grid-column:1/-1;grid-row:3;z-index:1000;display:flex;flex-direction:column}
@@ -1,2 +1,2 @@
1
- var L=Object.defineProperty;var t=(K,c)=>L(K,"name",{value:c,configurable:!0});import{bx as V,E as S,c as k,d as u,F as N,y as R,z as l,q as U,k as n,A as h,u as f,by as s,r as b,dI as G,h as J,j as $,l as Q,e as r,I as W,s as X}from"./vendor-other-B8t_Wf2K.js";import{w as z,u as Y,ad as Z,ae as w,y as P,e as ee,s as ie,af as ae}from"./vendor-primevue-Bp7MMXLP.js";import{u as ne}from"./vendor-vue-DaLZjKA7.js";import{bu as le,A as se,n as te,_ as p,S as de,du as oe,cE as re,cD as ue,d as ce}from"./index-DvCHS_f2.js";import{u as ye}from"./keybindingService-D3pQ4cJG.js";import"./vendor-xterm-CWYFmgbN.js";import"./vendor-three-DH0o8VQ7.js";import"./vendor-tiptap-VxK0yxkd.js";const be={key:0,class:"px-2"},fe=V({__name:"KeyComboDisplay",props:{keyCombo:{},isModified:{type:Boolean,default:!1}},setup(K){const c=S(()=>K.keyCombo.getKeySequences());return(d,m)=>(u(),k("span",null,[(u(!0),k(N,null,R(c.value,(_,C)=>(u(),k(N,{key:C},[l(s(z),{severity:d.isModified?"info":"secondary"},{default:n(()=>[h(f(_),1)]),_:2},1032,["severity"]),C<c.value.length-1?(u(),k("span",be,"+")):U("",!0)],64))),128))]))}}),me={class:"actions invisible flex flex-row"},ge=["title"],ve={key:1},pe={class:"overflow-hidden text-ellipsis"},ke=V({__name:"KeybindingPanel",setup(K){const c=b({global:{value:"",matchMode:ae.CONTAINS}}),d=le(),m=ye(),_=se(),{t:C}=ne(),D=S(()=>Object.values(_.commands).map(e=>({id:e.id,label:C(`commands.${te(e.id)}.label`,e.label??""),keybinding:d.getKeybindingByCommandId(e.id),source:e.source}))),E=b(null),g=b(!1),o=b(null),y=b(null),A=b(null),v=S(()=>!y.value||y.value.keybinding?.combo?.equals(o.value)||!o.value?null:d.getKeybinding(o.value));function B(e){y.value=e,o.value=e.keybinding?e.keybinding.combo:null,g.value=!0}t(B,"editKeybinding"),G(()=>{g.value&&setTimeout(()=>{A.value?.$el?.focus()},300)});async function F(e){e.keybinding&&(d.unsetKeybinding(e.keybinding),await m.persistUserKeybindings())}t(F,"removeKeybinding");async function T(e){if(!e.shiftKey&&!e.altKey&&!e.ctrlKey&&!e.metaKey)switch(e.key){case"Escape":I();return;case"Enter":await x();return}const a=re.fromEvent(e);o.value=a}t(T,"captureKeybinding");function I(){g.value=!1,y.value=null,o.value=null}t(I,"cancelEdit");async function x(){y.value&&o.value&&d.updateKeybindingOnCommand(new ue({commandId:y.value.id,combo:o.value}))&&await m.persistUserKeybindings(),I()}t(x,"saveKeybinding");async function q(e){d.resetKeybindingForCommand(e.id)?await m.persistUserKeybindings():console.warn(`No changes made when resetting keybinding for command: ${e.id}`)}t(q,"resetKeybinding");const O=Y();async function j(){d.resetAllKeybindings(),await m.persistUserKeybindings(),O.add({severity:"info",summary:"Info",detail:"All keybindings reset",life:3e3})}return t(j,"resetAllKeybindings"),(e,a)=>{const H=J("tooltip");return u(),$(oe,{value:"Keybinding",class:"keybinding-panel"},{header:n(()=>[l(de,{modelValue:c.value.global.value,"onUpdate:modelValue":a[0]||(a[0]=i=>c.value.global.value=i),placeholder:e.$t("g.searchKeybindings")+"..."},null,8,["modelValue","placeholder"])]),default:n(()=>[l(s(Z),{selection:E.value,"onUpdate:selection":a[1]||(a[1]=i=>E.value=i),value:D.value,"global-filter-fields":["id","label"],filters:c.value,"selection-mode":"single","striped-rows":"",pt:{header:"px-0"},onRowDblclick:a[2]||(a[2]=i=>B(i.data))},{default:n(()=>[l(s(w),{field:"actions",header:""},{body:n(i=>[r("div",me,[l(p,{variant:"textonly",size:"icon","aria-label":e.$t("g.edit"),onClick:t(M=>B(i.data),"onClick")},{default:n(()=>a[4]||(a[4]=[r("i",{class:"pi pi-pencil"},null,-1)])),_:2},1032,["aria-label","onClick"]),l(p,{variant:"textonly",size:"icon","aria-label":e.$t("g.reset"),disabled:!s(d).isCommandKeybindingModified(i.data.id),onClick:t(M=>q(i.data),"onClick")},{default:n(()=>a[5]||(a[5]=[r("i",{class:"pi pi-replay"},null,-1)])),_:2},1032,["aria-label","disabled","onClick"]),l(p,{variant:"textonly",size:"icon","aria-label":e.$t("g.delete"),disabled:!i.data.keybinding,onClick:t(M=>F(i.data),"onClick")},{default:n(()=>a[6]||(a[6]=[r("i",{class:"pi pi-trash"},null,-1)])),_:2},1032,["aria-label","disabled","onClick"])])]),_:1}),l(s(w),{field:"id",header:e.$t("g.command"),sortable:"",class:"max-w-64 2xl:max-w-full"},{body:n(i=>[r("div",{class:"truncate",title:i.data.id},f(i.data.label),9,ge)]),_:1},8,["header"]),l(s(w),{field:"keybinding",header:e.$t("g.keybinding")},{body:n(i=>[i.data.keybinding?(u(),$(fe,{key:0,"key-combo":i.data.keybinding.combo,"is-modified":s(d).isCommandKeybindingModified(i.data.id)},null,8,["key-combo","is-modified"])):(u(),k("span",ve,"-"))]),_:1},8,["header"]),l(s(w),{field:"source",header:e.$t("g.source")},{body:n(i=>[r("span",pe,f(i.data.source||"-"),1)]),_:1},8,["header"])]),_:1},8,["selection","value","filters"]),l(s(P),{visible:g.value,"onUpdate:visible":a[3]||(a[3]=i=>g.value=i),class:"min-w-96",modal:"",header:y.value?.label,onHide:I},{footer:n(()=>[l(p,{variant:v.value?"destructive":"primary",autofocus:"",onClick:x},{default:n(()=>[r("i",{class:X(v.value?"pi pi-pencil":"pi pi-check")},null,2),h(" "+f(v.value?e.$t("g.overwrite"):e.$t("g.save")),1)]),_:1},8,["variant"])]),default:n(()=>[r("div",null,[l(s(ee),{ref_key:"keybindingInput",ref:A,class:"mb-2 text-center","model-value":o.value?.toString()??"",placeholder:e.$t("g.pressKeysForNewBinding"),autocomplete:"off",fluid:"",onKeydown:W(T,["stop","prevent"])},null,8,["model-value","placeholder"]),v.value?(u(),$(s(ie),{key:0,severity:"warn"},{default:n(()=>[h(f(e.$t("g.keybindingAlreadyExists"))+" ",1),l(s(z),{severity:"secondary",value:v.value.commandId},null,8,["value"])]),_:1})):U("",!0)])]),_:1},8,["visible","header"]),Q((u(),$(p,{class:"mt-4 w-full",variant:"destructive-textonly",onClick:j},{default:n(()=>[a[7]||(a[7]=r("i",{class:"pi pi-replay"},null,-1)),h(" "+f(e.$t("g.resetAll")),1)]),_:1})),[[H,e.$t("g.resetAllKeybindingsTooltip")]])]),_:1})}}}),Ae=ce(ke,[["__scopeId","data-v-06049058"]]);export{Ae as default};
2
- //# sourceMappingURL=KeybindingPanel-Dm6H1RN2.js.map
1
+ var L=Object.defineProperty;var t=(K,c)=>L(K,"name",{value:c,configurable:!0});import{bx as V,E as S,c as k,d as u,F as N,y as R,z as l,q as U,k as n,A as h,u as f,by as s,r as b,dI as G,h as J,j as $,l as Q,e as r,I as W,s as X}from"./vendor-other-B8t_Wf2K.js";import{w as z,u as Y,ad as Z,ae as w,y as P,e as ee,s as ie,af as ae}from"./vendor-primevue-DeKsC2uk.js";import{u as ne}from"./vendor-vue-DaLZjKA7.js";import{bv as le,A as se,n as te,_ as p,S as de,du as oe,cE as re,cD as ue,d as ce}from"./index-BFHZsBkN.js";import{u as ye}from"./keybindingService-B_cUhEnt.js";import"./vendor-xterm-CWYFmgbN.js";import"./vendor-three-DH0o8VQ7.js";import"./vendor-tiptap-VxK0yxkd.js";const be={key:0,class:"px-2"},fe=V({__name:"KeyComboDisplay",props:{keyCombo:{},isModified:{type:Boolean,default:!1}},setup(K){const c=S(()=>K.keyCombo.getKeySequences());return(d,m)=>(u(),k("span",null,[(u(!0),k(N,null,R(c.value,(_,C)=>(u(),k(N,{key:C},[l(s(z),{severity:d.isModified?"info":"secondary"},{default:n(()=>[h(f(_),1)]),_:2},1032,["severity"]),C<c.value.length-1?(u(),k("span",be,"+")):U("",!0)],64))),128))]))}}),me={class:"actions invisible flex flex-row"},ve=["title"],ge={key:1},pe={class:"overflow-hidden text-ellipsis"},ke=V({__name:"KeybindingPanel",setup(K){const c=b({global:{value:"",matchMode:ae.CONTAINS}}),d=le(),m=ye(),_=se(),{t:C}=ne(),D=S(()=>Object.values(_.commands).map(e=>({id:e.id,label:C(`commands.${te(e.id)}.label`,e.label??""),keybinding:d.getKeybindingByCommandId(e.id),source:e.source}))),E=b(null),v=b(!1),o=b(null),y=b(null),A=b(null),g=S(()=>!y.value||y.value.keybinding?.combo?.equals(o.value)||!o.value?null:d.getKeybinding(o.value));function B(e){y.value=e,o.value=e.keybinding?e.keybinding.combo:null,v.value=!0}t(B,"editKeybinding"),G(()=>{v.value&&setTimeout(()=>{A.value?.$el?.focus()},300)});async function F(e){e.keybinding&&(d.unsetKeybinding(e.keybinding),await m.persistUserKeybindings())}t(F,"removeKeybinding");async function T(e){if(!e.shiftKey&&!e.altKey&&!e.ctrlKey&&!e.metaKey)switch(e.key){case"Escape":I();return;case"Enter":await x();return}const a=re.fromEvent(e);o.value=a}t(T,"captureKeybinding");function I(){v.value=!1,y.value=null,o.value=null}t(I,"cancelEdit");async function x(){y.value&&o.value&&d.updateKeybindingOnCommand(new ue({commandId:y.value.id,combo:o.value}))&&await m.persistUserKeybindings(),I()}t(x,"saveKeybinding");async function q(e){d.resetKeybindingForCommand(e.id)?await m.persistUserKeybindings():console.warn(`No changes made when resetting keybinding for command: ${e.id}`)}t(q,"resetKeybinding");const O=Y();async function j(){d.resetAllKeybindings(),await m.persistUserKeybindings(),O.add({severity:"info",summary:"Info",detail:"All keybindings reset",life:3e3})}return t(j,"resetAllKeybindings"),(e,a)=>{const H=J("tooltip");return u(),$(oe,{value:"Keybinding",class:"keybinding-panel"},{header:n(()=>[l(de,{modelValue:c.value.global.value,"onUpdate:modelValue":a[0]||(a[0]=i=>c.value.global.value=i),placeholder:e.$t("g.searchKeybindings")+"..."},null,8,["modelValue","placeholder"])]),default:n(()=>[l(s(Z),{selection:E.value,"onUpdate:selection":a[1]||(a[1]=i=>E.value=i),value:D.value,"global-filter-fields":["id","label"],filters:c.value,"selection-mode":"single","striped-rows":"",pt:{header:"px-0"},onRowDblclick:a[2]||(a[2]=i=>B(i.data))},{default:n(()=>[l(s(w),{field:"actions",header:""},{body:n(i=>[r("div",me,[l(p,{variant:"textonly",size:"icon","aria-label":e.$t("g.edit"),onClick:t(M=>B(i.data),"onClick")},{default:n(()=>a[4]||(a[4]=[r("i",{class:"pi pi-pencil"},null,-1)])),_:2},1032,["aria-label","onClick"]),l(p,{variant:"textonly",size:"icon","aria-label":e.$t("g.reset"),disabled:!s(d).isCommandKeybindingModified(i.data.id),onClick:t(M=>q(i.data),"onClick")},{default:n(()=>a[5]||(a[5]=[r("i",{class:"pi pi-replay"},null,-1)])),_:2},1032,["aria-label","disabled","onClick"]),l(p,{variant:"textonly",size:"icon","aria-label":e.$t("g.delete"),disabled:!i.data.keybinding,onClick:t(M=>F(i.data),"onClick")},{default:n(()=>a[6]||(a[6]=[r("i",{class:"pi pi-trash"},null,-1)])),_:2},1032,["aria-label","disabled","onClick"])])]),_:1}),l(s(w),{field:"id",header:e.$t("g.command"),sortable:"",class:"max-w-64 2xl:max-w-full"},{body:n(i=>[r("div",{class:"truncate",title:i.data.id},f(i.data.label),9,ve)]),_:1},8,["header"]),l(s(w),{field:"keybinding",header:e.$t("g.keybinding")},{body:n(i=>[i.data.keybinding?(u(),$(fe,{key:0,"key-combo":i.data.keybinding.combo,"is-modified":s(d).isCommandKeybindingModified(i.data.id)},null,8,["key-combo","is-modified"])):(u(),k("span",ge,"-"))]),_:1},8,["header"]),l(s(w),{field:"source",header:e.$t("g.source")},{body:n(i=>[r("span",pe,f(i.data.source||"-"),1)]),_:1},8,["header"])]),_:1},8,["selection","value","filters"]),l(s(P),{visible:v.value,"onUpdate:visible":a[3]||(a[3]=i=>v.value=i),class:"min-w-96",modal:"",header:y.value?.label,onHide:I},{footer:n(()=>[l(p,{variant:g.value?"destructive":"primary",autofocus:"",onClick:x},{default:n(()=>[r("i",{class:X(g.value?"pi pi-pencil":"pi pi-check")},null,2),h(" "+f(g.value?e.$t("g.overwrite"):e.$t("g.save")),1)]),_:1},8,["variant"])]),default:n(()=>[r("div",null,[l(s(ee),{ref_key:"keybindingInput",ref:A,class:"mb-2 text-center","model-value":o.value?.toString()??"",placeholder:e.$t("g.pressKeysForNewBinding"),autocomplete:"off",fluid:"",onKeydown:W(T,["stop","prevent"])},null,8,["model-value","placeholder"]),g.value?(u(),$(s(ie),{key:0,severity:"warn"},{default:n(()=>[h(f(e.$t("g.keybindingAlreadyExists"))+" ",1),l(s(z),{severity:"secondary",value:g.value.commandId},null,8,["value"])]),_:1})):U("",!0)])]),_:1},8,["visible","header"]),Q((u(),$(p,{class:"mt-4 w-full",variant:"destructive-textonly",onClick:j},{default:n(()=>[a[7]||(a[7]=r("i",{class:"pi pi-replay"},null,-1)),h(" "+f(e.$t("g.resetAll")),1)]),_:1})),[[H,e.$t("g.resetAllKeybindingsTooltip")]])]),_:1})}}}),Ae=ce(ke,[["__scopeId","data-v-06049058"]]);export{Ae as default};
2
+ //# sourceMappingURL=KeybindingPanel-DtxoTOoX.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"KeybindingPanel-Dm6H1RN2.js","sources":["../../src/components/dialog/content/setting/keybinding/KeyComboDisplay.vue","../../src/components/dialog/content/setting/KeybindingPanel.vue"],"sourcesContent":["<template>\n <span>\n <template v-for=\"(sequence, index) in keySequences\" :key=\"index\">\n <Tag :severity=\"isModified ? 'info' : 'secondary'\">\n {{ sequence }}\n </Tag>\n <span v-if=\"index < keySequences.length - 1\" class=\"px-2\">+</span>\n </template>\n </span>\n</template>\n\n<script setup lang=\"ts\">\nimport Tag from 'primevue/tag'\nimport { computed } from 'vue'\n\nimport type { KeyComboImpl } from '@/stores/keybindingStore'\n\nconst { keyCombo, isModified = false } = defineProps<{\n keyCombo: KeyComboImpl\n isModified?: boolean\n}>()\n\nconst keySequences = computed(() => keyCombo.getKeySequences())\n</script>\n","<template>\n <PanelTemplate value=\"Keybinding\" class=\"keybinding-panel\">\n <template #header>\n <SearchBox\n v-model=\"filters['global'].value\"\n :placeholder=\"$t('g.searchKeybindings') + '...'\"\n />\n </template>\n\n <DataTable\n v-model:selection=\"selectedCommandData\"\n :value=\"commandsData\"\n :global-filter-fields=\"['id', 'label']\"\n :filters=\"filters\"\n selection-mode=\"single\"\n striped-rows\n :pt=\"{\n header: 'px-0'\n }\"\n @row-dblclick=\"editKeybinding($event.data)\"\n >\n <Column field=\"actions\" header=\"\">\n <template #body=\"slotProps\">\n <div class=\"actions invisible flex flex-row\">\n <Button\n variant=\"textonly\"\n size=\"icon\"\n :aria-label=\"$t('g.edit')\"\n @click=\"editKeybinding(slotProps.data)\"\n >\n <i class=\"pi pi-pencil\" />\n </Button>\n <Button\n variant=\"textonly\"\n size=\"icon\"\n :aria-label=\"$t('g.reset')\"\n :disabled=\"\n !keybindingStore.isCommandKeybindingModified(slotProps.data.id)\n \"\n @click=\"resetKeybinding(slotProps.data)\"\n >\n <i class=\"pi pi-replay\" />\n </Button>\n <Button\n variant=\"textonly\"\n size=\"icon\"\n :aria-label=\"$t('g.delete')\"\n :disabled=\"!slotProps.data.keybinding\"\n @click=\"removeKeybinding(slotProps.data)\"\n >\n <i class=\"pi pi-trash\" />\n </Button>\n </div>\n </template>\n </Column>\n <Column\n field=\"id\"\n :header=\"$t('g.command')\"\n sortable\n class=\"max-w-64 2xl:max-w-full\"\n >\n <template #body=\"slotProps\">\n <div class=\"truncate\" :title=\"slotProps.data.id\">\n {{ slotProps.data.label }}\n </div>\n </template>\n </Column>\n <Column field=\"keybinding\" :header=\"$t('g.keybinding')\">\n <template #body=\"slotProps\">\n <KeyComboDisplay\n v-if=\"slotProps.data.keybinding\"\n :key-combo=\"slotProps.data.keybinding.combo\"\n :is-modified=\"\n keybindingStore.isCommandKeybindingModified(slotProps.data.id)\n \"\n />\n <span v-else>-</span>\n </template>\n </Column>\n <Column field=\"source\" :header=\"$t('g.source')\">\n <template #body=\"slotProps\">\n <span class=\"overflow-hidden text-ellipsis\">{{\n slotProps.data.source || '-'\n }}</span>\n </template>\n </Column>\n </DataTable>\n\n <Dialog\n v-model:visible=\"editDialogVisible\"\n class=\"min-w-96\"\n modal\n :header=\"currentEditingCommand?.label\"\n @hide=\"cancelEdit\"\n >\n <div>\n <InputText\n ref=\"keybindingInput\"\n class=\"mb-2 text-center\"\n :model-value=\"newBindingKeyCombo?.toString() ?? ''\"\n :placeholder=\"$t('g.pressKeysForNewBinding')\"\n autocomplete=\"off\"\n fluid\n @keydown.stop.prevent=\"captureKeybinding\"\n />\n <Message v-if=\"existingKeybindingOnCombo\" severity=\"warn\">\n {{ $t('g.keybindingAlreadyExists') }}\n <Tag\n severity=\"secondary\"\n :value=\"existingKeybindingOnCombo.commandId\"\n />\n </Message>\n </div>\n <template #footer>\n <Button\n :variant=\"existingKeybindingOnCombo ? 'destructive' : 'primary'\"\n autofocus\n @click=\"saveKeybinding\"\n >\n <i\n :class=\"existingKeybindingOnCombo ? 'pi pi-pencil' : 'pi pi-check'\"\n />\n {{ existingKeybindingOnCombo ? $t('g.overwrite') : $t('g.save') }}\n </Button>\n </template>\n </Dialog>\n <Button\n v-tooltip=\"$t('g.resetAllKeybindingsTooltip')\"\n class=\"mt-4 w-full\"\n variant=\"destructive-textonly\"\n @click=\"resetAllKeybindings\"\n >\n <i class=\"pi pi-replay\" />\n {{ $t('g.resetAll') }}\n </Button>\n </PanelTemplate>\n</template>\n\n<script setup lang=\"ts\">\nimport { FilterMatchMode } from '@primevue/core/api'\nimport Column from 'primevue/column'\nimport DataTable from 'primevue/datatable'\nimport Dialog from 'primevue/dialog'\nimport InputText from 'primevue/inputtext'\nimport Message from 'primevue/message'\nimport Tag from 'primevue/tag'\nimport { useToast } from 'primevue/usetoast'\nimport { computed, ref, watchEffect } from 'vue'\nimport { useI18n } from 'vue-i18n'\n\nimport SearchBox from '@/components/common/SearchBox.vue'\nimport Button from '@/components/ui/button/Button.vue'\nimport { useKeybindingService } from '@/services/keybindingService'\nimport { useCommandStore } from '@/stores/commandStore'\nimport {\n KeyComboImpl,\n KeybindingImpl,\n useKeybindingStore\n} from '@/stores/keybindingStore'\nimport { normalizeI18nKey } from '@/utils/formatUtil'\n\nimport PanelTemplate from './PanelTemplate.vue'\nimport KeyComboDisplay from './keybinding/KeyComboDisplay.vue'\n\nconst filters = ref({\n global: { value: '', matchMode: FilterMatchMode.CONTAINS }\n})\n\nconst keybindingStore = useKeybindingStore()\nconst keybindingService = useKeybindingService()\nconst commandStore = useCommandStore()\nconst { t } = useI18n()\n\ninterface ICommandData {\n id: string\n keybinding: KeybindingImpl | null\n label: string\n source?: string\n}\n\nconst commandsData = computed<ICommandData[]>(() => {\n return Object.values(commandStore.commands).map((command) => ({\n id: command.id,\n label: t(\n `commands.${normalizeI18nKey(command.id)}.label`,\n command.label ?? ''\n ),\n keybinding: keybindingStore.getKeybindingByCommandId(command.id),\n source: command.source\n }))\n})\n\nconst selectedCommandData = ref<ICommandData | null>(null)\nconst editDialogVisible = ref(false)\nconst newBindingKeyCombo = ref<KeyComboImpl | null>(null)\nconst currentEditingCommand = ref<ICommandData | null>(null)\nconst keybindingInput = ref<InstanceType<typeof InputText> | null>(null)\n\nconst existingKeybindingOnCombo = computed<KeybindingImpl | null>(() => {\n if (!currentEditingCommand.value) {\n return null\n }\n\n // If the new keybinding is the same as the current editing command, then don't show the error\n if (\n currentEditingCommand.value.keybinding?.combo?.equals(\n newBindingKeyCombo.value\n )\n ) {\n return null\n }\n\n if (!newBindingKeyCombo.value) {\n return null\n }\n\n return keybindingStore.getKeybinding(newBindingKeyCombo.value)\n})\n\nfunction editKeybinding(commandData: ICommandData) {\n currentEditingCommand.value = commandData\n newBindingKeyCombo.value = commandData.keybinding\n ? commandData.keybinding.combo\n : null\n editDialogVisible.value = true\n}\n\nwatchEffect(() => {\n if (editDialogVisible.value) {\n // nextTick doesn't work here, so we use a timeout instead\n setTimeout(() => {\n // @ts-expect-error - $el is an internal property of the InputText component\n keybindingInput.value?.$el?.focus()\n }, 300)\n }\n})\n\nasync function removeKeybinding(commandData: ICommandData) {\n if (commandData.keybinding) {\n keybindingStore.unsetKeybinding(commandData.keybinding)\n await keybindingService.persistUserKeybindings()\n }\n}\n\nasync function captureKeybinding(event: KeyboardEvent) {\n // Allow the use of keyboard shortcuts when adding keyboard shortcuts\n if (!event.shiftKey && !event.altKey && !event.ctrlKey && !event.metaKey) {\n switch (event.key) {\n case 'Escape':\n cancelEdit()\n return\n case 'Enter':\n await saveKeybinding()\n return\n }\n }\n const keyCombo = KeyComboImpl.fromEvent(event)\n newBindingKeyCombo.value = keyCombo\n}\n\nfunction cancelEdit() {\n editDialogVisible.value = false\n currentEditingCommand.value = null\n newBindingKeyCombo.value = null\n}\n\nasync function saveKeybinding() {\n if (currentEditingCommand.value && newBindingKeyCombo.value) {\n const updated = keybindingStore.updateKeybindingOnCommand(\n new KeybindingImpl({\n commandId: currentEditingCommand.value.id,\n combo: newBindingKeyCombo.value\n })\n )\n if (updated) {\n await keybindingService.persistUserKeybindings()\n }\n }\n cancelEdit()\n}\n\nasync function resetKeybinding(commandData: ICommandData) {\n if (keybindingStore.resetKeybindingForCommand(commandData.id)) {\n await keybindingService.persistUserKeybindings()\n } else {\n console.warn(\n `No changes made when resetting keybinding for command: ${commandData.id}`\n )\n }\n}\n\nconst toast = useToast()\nasync function resetAllKeybindings() {\n keybindingStore.resetAllKeybindings()\n await keybindingService.persistUserKeybindings()\n toast.add({\n severity: 'info',\n summary: 'Info',\n detail: 'All keybindings reset',\n life: 3000\n })\n}\n</script>\n\n<style scoped>\n@reference '../../../../assets/css/style.css';\n\n:deep(.p-datatable-tbody) > tr > td {\n @apply p-1;\n min-height: 2rem;\n}\n\n:deep(.p-datatable-row-selected) .actions,\n:deep(.p-datatable-selectable-row:hover) .actions {\n @apply visible;\n}\n</style>\n"],"names":["keySequences","computed","__props","filters","ref","FilterMatchMode","keybindingStore","useKeybindingStore","keybindingService","useKeybindingService","commandStore","useCommandStore","t","useI18n","commandsData","command","normalizeI18nKey","selectedCommandData","editDialogVisible","newBindingKeyCombo","currentEditingCommand","keybindingInput","existingKeybindingOnCombo","editKeybinding","commandData","__name","watchEffect","removeKeybinding","captureKeybinding","event","cancelEdit","saveKeybinding","keyCombo","KeyComboImpl","KeybindingImpl","resetKeybinding","toast","useToast","resetAllKeybindings"],"mappings":"uyBAsBA,MAAMA,EAAeC,EAAS,IAAMC,EAAA,SAAS,iBAAiB,0ZC8I9D,MAAMC,EAAUC,EAAI,CAClB,OAAQ,CAAE,MAAO,GAAI,UAAWC,GAAgB,QAAA,CAAS,CAC1D,EAEKC,EAAkBC,GAAA,EAClBC,EAAoBC,GAAA,EACpBC,EAAeC,GAAA,EACf,CAAE,EAAAC,CAAA,EAAMC,GAAA,EASRC,EAAeb,EAAyB,IACrC,OAAO,OAAOS,EAAa,QAAQ,EAAE,IAAKK,IAAa,CAC5D,GAAIA,EAAQ,GACZ,MAAOH,EACL,YAAYI,GAAiBD,EAAQ,EAAE,CAAC,SACxCA,EAAQ,OAAS,EAAA,EAEnB,WAAYT,EAAgB,yBAAyBS,EAAQ,EAAE,EAC/D,OAAQA,EAAQ,MAAA,EAChB,CACH,EAEKE,EAAsBb,EAAyB,IAAI,EACnDc,EAAoBd,EAAI,EAAK,EAC7Be,EAAqBf,EAAyB,IAAI,EAClDgB,EAAwBhB,EAAyB,IAAI,EACrDiB,EAAkBjB,EAA2C,IAAI,EAEjEkB,EAA4BrB,EAAgC,IAC5D,CAACmB,EAAsB,OAMzBA,EAAsB,MAAM,YAAY,OAAO,OAC7CD,EAAmB,KAAA,GAMnB,CAACA,EAAmB,MACf,KAGFb,EAAgB,cAAca,EAAmB,KAAK,CAC9D,EAED,SAASI,EAAeC,EAA2B,CACjDJ,EAAsB,MAAQI,EAC9BL,EAAmB,MAAQK,EAAY,WACnCA,EAAY,WAAW,MACvB,KACJN,EAAkB,MAAQ,EAC5B,CANSO,EAAAF,EAAA,kBAQTG,EAAY,IAAM,CACZR,EAAkB,OAEpB,WAAW,IAAM,CAEfG,EAAgB,OAAO,KAAK,MAAA,CAC9B,EAAG,GAAG,CAEV,CAAC,EAED,eAAeM,EAAiBH,EAA2B,CACrDA,EAAY,aACdlB,EAAgB,gBAAgBkB,EAAY,UAAU,EACtD,MAAMhB,EAAkB,uBAAA,EAE5B,CALeiB,EAAAE,EAAA,oBAOf,eAAeC,EAAkBC,EAAsB,CAErD,GAAI,CAACA,EAAM,UAAY,CAACA,EAAM,QAAU,CAACA,EAAM,SAAW,CAACA,EAAM,QAC/D,OAAQA,EAAM,IAAA,CACZ,IAAK,SACHC,EAAA,EACA,OACF,IAAK,QACH,MAAMC,EAAA,EACN,MAAA,CAGN,MAAMC,EAAWC,GAAa,UAAUJ,CAAK,EAC7CV,EAAmB,MAAQa,CAC7B,CAdeP,EAAAG,EAAA,qBAgBf,SAASE,GAAa,CACpBZ,EAAkB,MAAQ,GAC1BE,EAAsB,MAAQ,KAC9BD,EAAmB,MAAQ,IAC7B,CAJSM,EAAAK,EAAA,cAMT,eAAeC,GAAiB,CAC1BX,EAAsB,OAASD,EAAmB,OACpCb,EAAgB,0BAC9B,IAAI4B,GAAe,CACjB,UAAWd,EAAsB,MAAM,GACvC,MAAOD,EAAmB,KAAA,CAC3B,CAAA,GAGD,MAAMX,EAAkB,uBAAA,EAG5BsB,EAAA,CACF,CAbeL,EAAAM,EAAA,kBAef,eAAeI,EAAgBX,EAA2B,CACpDlB,EAAgB,0BAA0BkB,EAAY,EAAE,EAC1D,MAAMhB,EAAkB,uBAAA,EAExB,QAAQ,KACN,0DAA0DgB,EAAY,EAAE,EAAA,CAG9E,CAReC,EAAAU,EAAA,mBAUf,MAAMC,EAAQC,EAAA,EACd,eAAeC,GAAsB,CACnChC,EAAgB,oBAAA,EAChB,MAAME,EAAkB,uBAAA,EACxB4B,EAAM,IAAI,CACR,SAAU,OACV,QAAS,OACT,OAAQ,wBACR,KAAM,GAAA,CACP,CACH,CATe,OAAAX,EAAAa,EAAA"}
1
+ {"version":3,"file":"KeybindingPanel-DtxoTOoX.js","sources":["../../src/components/dialog/content/setting/keybinding/KeyComboDisplay.vue","../../src/components/dialog/content/setting/KeybindingPanel.vue"],"sourcesContent":["<template>\n <span>\n <template v-for=\"(sequence, index) in keySequences\" :key=\"index\">\n <Tag :severity=\"isModified ? 'info' : 'secondary'\">\n {{ sequence }}\n </Tag>\n <span v-if=\"index < keySequences.length - 1\" class=\"px-2\">+</span>\n </template>\n </span>\n</template>\n\n<script setup lang=\"ts\">\nimport Tag from 'primevue/tag'\nimport { computed } from 'vue'\n\nimport type { KeyComboImpl } from '@/stores/keybindingStore'\n\nconst { keyCombo, isModified = false } = defineProps<{\n keyCombo: KeyComboImpl\n isModified?: boolean\n}>()\n\nconst keySequences = computed(() => keyCombo.getKeySequences())\n</script>\n","<template>\n <PanelTemplate value=\"Keybinding\" class=\"keybinding-panel\">\n <template #header>\n <SearchBox\n v-model=\"filters['global'].value\"\n :placeholder=\"$t('g.searchKeybindings') + '...'\"\n />\n </template>\n\n <DataTable\n v-model:selection=\"selectedCommandData\"\n :value=\"commandsData\"\n :global-filter-fields=\"['id', 'label']\"\n :filters=\"filters\"\n selection-mode=\"single\"\n striped-rows\n :pt=\"{\n header: 'px-0'\n }\"\n @row-dblclick=\"editKeybinding($event.data)\"\n >\n <Column field=\"actions\" header=\"\">\n <template #body=\"slotProps\">\n <div class=\"actions invisible flex flex-row\">\n <Button\n variant=\"textonly\"\n size=\"icon\"\n :aria-label=\"$t('g.edit')\"\n @click=\"editKeybinding(slotProps.data)\"\n >\n <i class=\"pi pi-pencil\" />\n </Button>\n <Button\n variant=\"textonly\"\n size=\"icon\"\n :aria-label=\"$t('g.reset')\"\n :disabled=\"\n !keybindingStore.isCommandKeybindingModified(slotProps.data.id)\n \"\n @click=\"resetKeybinding(slotProps.data)\"\n >\n <i class=\"pi pi-replay\" />\n </Button>\n <Button\n variant=\"textonly\"\n size=\"icon\"\n :aria-label=\"$t('g.delete')\"\n :disabled=\"!slotProps.data.keybinding\"\n @click=\"removeKeybinding(slotProps.data)\"\n >\n <i class=\"pi pi-trash\" />\n </Button>\n </div>\n </template>\n </Column>\n <Column\n field=\"id\"\n :header=\"$t('g.command')\"\n sortable\n class=\"max-w-64 2xl:max-w-full\"\n >\n <template #body=\"slotProps\">\n <div class=\"truncate\" :title=\"slotProps.data.id\">\n {{ slotProps.data.label }}\n </div>\n </template>\n </Column>\n <Column field=\"keybinding\" :header=\"$t('g.keybinding')\">\n <template #body=\"slotProps\">\n <KeyComboDisplay\n v-if=\"slotProps.data.keybinding\"\n :key-combo=\"slotProps.data.keybinding.combo\"\n :is-modified=\"\n keybindingStore.isCommandKeybindingModified(slotProps.data.id)\n \"\n />\n <span v-else>-</span>\n </template>\n </Column>\n <Column field=\"source\" :header=\"$t('g.source')\">\n <template #body=\"slotProps\">\n <span class=\"overflow-hidden text-ellipsis\">{{\n slotProps.data.source || '-'\n }}</span>\n </template>\n </Column>\n </DataTable>\n\n <Dialog\n v-model:visible=\"editDialogVisible\"\n class=\"min-w-96\"\n modal\n :header=\"currentEditingCommand?.label\"\n @hide=\"cancelEdit\"\n >\n <div>\n <InputText\n ref=\"keybindingInput\"\n class=\"mb-2 text-center\"\n :model-value=\"newBindingKeyCombo?.toString() ?? ''\"\n :placeholder=\"$t('g.pressKeysForNewBinding')\"\n autocomplete=\"off\"\n fluid\n @keydown.stop.prevent=\"captureKeybinding\"\n />\n <Message v-if=\"existingKeybindingOnCombo\" severity=\"warn\">\n {{ $t('g.keybindingAlreadyExists') }}\n <Tag\n severity=\"secondary\"\n :value=\"existingKeybindingOnCombo.commandId\"\n />\n </Message>\n </div>\n <template #footer>\n <Button\n :variant=\"existingKeybindingOnCombo ? 'destructive' : 'primary'\"\n autofocus\n @click=\"saveKeybinding\"\n >\n <i\n :class=\"existingKeybindingOnCombo ? 'pi pi-pencil' : 'pi pi-check'\"\n />\n {{ existingKeybindingOnCombo ? $t('g.overwrite') : $t('g.save') }}\n </Button>\n </template>\n </Dialog>\n <Button\n v-tooltip=\"$t('g.resetAllKeybindingsTooltip')\"\n class=\"mt-4 w-full\"\n variant=\"destructive-textonly\"\n @click=\"resetAllKeybindings\"\n >\n <i class=\"pi pi-replay\" />\n {{ $t('g.resetAll') }}\n </Button>\n </PanelTemplate>\n</template>\n\n<script setup lang=\"ts\">\nimport { FilterMatchMode } from '@primevue/core/api'\nimport Column from 'primevue/column'\nimport DataTable from 'primevue/datatable'\nimport Dialog from 'primevue/dialog'\nimport InputText from 'primevue/inputtext'\nimport Message from 'primevue/message'\nimport Tag from 'primevue/tag'\nimport { useToast } from 'primevue/usetoast'\nimport { computed, ref, watchEffect } from 'vue'\nimport { useI18n } from 'vue-i18n'\n\nimport SearchBox from '@/components/common/SearchBox.vue'\nimport Button from '@/components/ui/button/Button.vue'\nimport { useKeybindingService } from '@/services/keybindingService'\nimport { useCommandStore } from '@/stores/commandStore'\nimport {\n KeyComboImpl,\n KeybindingImpl,\n useKeybindingStore\n} from '@/stores/keybindingStore'\nimport { normalizeI18nKey } from '@/utils/formatUtil'\n\nimport PanelTemplate from './PanelTemplate.vue'\nimport KeyComboDisplay from './keybinding/KeyComboDisplay.vue'\n\nconst filters = ref({\n global: { value: '', matchMode: FilterMatchMode.CONTAINS }\n})\n\nconst keybindingStore = useKeybindingStore()\nconst keybindingService = useKeybindingService()\nconst commandStore = useCommandStore()\nconst { t } = useI18n()\n\ninterface ICommandData {\n id: string\n keybinding: KeybindingImpl | null\n label: string\n source?: string\n}\n\nconst commandsData = computed<ICommandData[]>(() => {\n return Object.values(commandStore.commands).map((command) => ({\n id: command.id,\n label: t(\n `commands.${normalizeI18nKey(command.id)}.label`,\n command.label ?? ''\n ),\n keybinding: keybindingStore.getKeybindingByCommandId(command.id),\n source: command.source\n }))\n})\n\nconst selectedCommandData = ref<ICommandData | null>(null)\nconst editDialogVisible = ref(false)\nconst newBindingKeyCombo = ref<KeyComboImpl | null>(null)\nconst currentEditingCommand = ref<ICommandData | null>(null)\nconst keybindingInput = ref<InstanceType<typeof InputText> | null>(null)\n\nconst existingKeybindingOnCombo = computed<KeybindingImpl | null>(() => {\n if (!currentEditingCommand.value) {\n return null\n }\n\n // If the new keybinding is the same as the current editing command, then don't show the error\n if (\n currentEditingCommand.value.keybinding?.combo?.equals(\n newBindingKeyCombo.value\n )\n ) {\n return null\n }\n\n if (!newBindingKeyCombo.value) {\n return null\n }\n\n return keybindingStore.getKeybinding(newBindingKeyCombo.value)\n})\n\nfunction editKeybinding(commandData: ICommandData) {\n currentEditingCommand.value = commandData\n newBindingKeyCombo.value = commandData.keybinding\n ? commandData.keybinding.combo\n : null\n editDialogVisible.value = true\n}\n\nwatchEffect(() => {\n if (editDialogVisible.value) {\n // nextTick doesn't work here, so we use a timeout instead\n setTimeout(() => {\n // @ts-expect-error - $el is an internal property of the InputText component\n keybindingInput.value?.$el?.focus()\n }, 300)\n }\n})\n\nasync function removeKeybinding(commandData: ICommandData) {\n if (commandData.keybinding) {\n keybindingStore.unsetKeybinding(commandData.keybinding)\n await keybindingService.persistUserKeybindings()\n }\n}\n\nasync function captureKeybinding(event: KeyboardEvent) {\n // Allow the use of keyboard shortcuts when adding keyboard shortcuts\n if (!event.shiftKey && !event.altKey && !event.ctrlKey && !event.metaKey) {\n switch (event.key) {\n case 'Escape':\n cancelEdit()\n return\n case 'Enter':\n await saveKeybinding()\n return\n }\n }\n const keyCombo = KeyComboImpl.fromEvent(event)\n newBindingKeyCombo.value = keyCombo\n}\n\nfunction cancelEdit() {\n editDialogVisible.value = false\n currentEditingCommand.value = null\n newBindingKeyCombo.value = null\n}\n\nasync function saveKeybinding() {\n if (currentEditingCommand.value && newBindingKeyCombo.value) {\n const updated = keybindingStore.updateKeybindingOnCommand(\n new KeybindingImpl({\n commandId: currentEditingCommand.value.id,\n combo: newBindingKeyCombo.value\n })\n )\n if (updated) {\n await keybindingService.persistUserKeybindings()\n }\n }\n cancelEdit()\n}\n\nasync function resetKeybinding(commandData: ICommandData) {\n if (keybindingStore.resetKeybindingForCommand(commandData.id)) {\n await keybindingService.persistUserKeybindings()\n } else {\n console.warn(\n `No changes made when resetting keybinding for command: ${commandData.id}`\n )\n }\n}\n\nconst toast = useToast()\nasync function resetAllKeybindings() {\n keybindingStore.resetAllKeybindings()\n await keybindingService.persistUserKeybindings()\n toast.add({\n severity: 'info',\n summary: 'Info',\n detail: 'All keybindings reset',\n life: 3000\n })\n}\n</script>\n\n<style scoped>\n@reference '../../../../assets/css/style.css';\n\n:deep(.p-datatable-tbody) > tr > td {\n @apply p-1;\n min-height: 2rem;\n}\n\n:deep(.p-datatable-row-selected) .actions,\n:deep(.p-datatable-selectable-row:hover) .actions {\n @apply visible;\n}\n</style>\n"],"names":["keySequences","computed","__props","filters","ref","FilterMatchMode","keybindingStore","useKeybindingStore","keybindingService","useKeybindingService","commandStore","useCommandStore","t","useI18n","commandsData","command","normalizeI18nKey","selectedCommandData","editDialogVisible","newBindingKeyCombo","currentEditingCommand","keybindingInput","existingKeybindingOnCombo","editKeybinding","commandData","__name","watchEffect","removeKeybinding","captureKeybinding","event","cancelEdit","saveKeybinding","keyCombo","KeyComboImpl","KeybindingImpl","resetKeybinding","toast","useToast","resetAllKeybindings"],"mappings":"uyBAsBA,MAAMA,EAAeC,EAAS,IAAMC,EAAA,SAAS,iBAAiB,0ZC8I9D,MAAMC,EAAUC,EAAI,CAClB,OAAQ,CAAE,MAAO,GAAI,UAAWC,GAAgB,QAAA,CAAS,CAC1D,EAEKC,EAAkBC,GAAA,EAClBC,EAAoBC,GAAA,EACpBC,EAAeC,GAAA,EACf,CAAE,EAAAC,CAAA,EAAMC,GAAA,EASRC,EAAeb,EAAyB,IACrC,OAAO,OAAOS,EAAa,QAAQ,EAAE,IAAKK,IAAa,CAC5D,GAAIA,EAAQ,GACZ,MAAOH,EACL,YAAYI,GAAiBD,EAAQ,EAAE,CAAC,SACxCA,EAAQ,OAAS,EAAA,EAEnB,WAAYT,EAAgB,yBAAyBS,EAAQ,EAAE,EAC/D,OAAQA,EAAQ,MAAA,EAChB,CACH,EAEKE,EAAsBb,EAAyB,IAAI,EACnDc,EAAoBd,EAAI,EAAK,EAC7Be,EAAqBf,EAAyB,IAAI,EAClDgB,EAAwBhB,EAAyB,IAAI,EACrDiB,EAAkBjB,EAA2C,IAAI,EAEjEkB,EAA4BrB,EAAgC,IAC5D,CAACmB,EAAsB,OAMzBA,EAAsB,MAAM,YAAY,OAAO,OAC7CD,EAAmB,KAAA,GAMnB,CAACA,EAAmB,MACf,KAGFb,EAAgB,cAAca,EAAmB,KAAK,CAC9D,EAED,SAASI,EAAeC,EAA2B,CACjDJ,EAAsB,MAAQI,EAC9BL,EAAmB,MAAQK,EAAY,WACnCA,EAAY,WAAW,MACvB,KACJN,EAAkB,MAAQ,EAC5B,CANSO,EAAAF,EAAA,kBAQTG,EAAY,IAAM,CACZR,EAAkB,OAEpB,WAAW,IAAM,CAEfG,EAAgB,OAAO,KAAK,MAAA,CAC9B,EAAG,GAAG,CAEV,CAAC,EAED,eAAeM,EAAiBH,EAA2B,CACrDA,EAAY,aACdlB,EAAgB,gBAAgBkB,EAAY,UAAU,EACtD,MAAMhB,EAAkB,uBAAA,EAE5B,CALeiB,EAAAE,EAAA,oBAOf,eAAeC,EAAkBC,EAAsB,CAErD,GAAI,CAACA,EAAM,UAAY,CAACA,EAAM,QAAU,CAACA,EAAM,SAAW,CAACA,EAAM,QAC/D,OAAQA,EAAM,IAAA,CACZ,IAAK,SACHC,EAAA,EACA,OACF,IAAK,QACH,MAAMC,EAAA,EACN,MAAA,CAGN,MAAMC,EAAWC,GAAa,UAAUJ,CAAK,EAC7CV,EAAmB,MAAQa,CAC7B,CAdeP,EAAAG,EAAA,qBAgBf,SAASE,GAAa,CACpBZ,EAAkB,MAAQ,GAC1BE,EAAsB,MAAQ,KAC9BD,EAAmB,MAAQ,IAC7B,CAJSM,EAAAK,EAAA,cAMT,eAAeC,GAAiB,CAC1BX,EAAsB,OAASD,EAAmB,OACpCb,EAAgB,0BAC9B,IAAI4B,GAAe,CACjB,UAAWd,EAAsB,MAAM,GACvC,MAAOD,EAAmB,KAAA,CAC3B,CAAA,GAGD,MAAMX,EAAkB,uBAAA,EAG5BsB,EAAA,CACF,CAbeL,EAAAM,EAAA,kBAef,eAAeI,EAAgBX,EAA2B,CACpDlB,EAAgB,0BAA0BkB,EAAY,EAAE,EAC1D,MAAMhB,EAAkB,uBAAA,EAExB,QAAQ,KACN,0DAA0DgB,EAAY,EAAE,EAAA,CAG9E,CAReC,EAAAU,EAAA,mBAUf,MAAMC,EAAQC,EAAA,EACd,eAAeC,GAAsB,CACnChC,EAAgB,oBAAA,EAChB,MAAME,EAAkB,uBAAA,EACxB4B,EAAM,IAAI,CACR,SAAU,OACV,QAAS,OACT,OAAQ,wBACR,KAAM,GAAA,CACP,CACH,CATe,OAAAX,EAAAa,EAAA"}
@@ -0,0 +1,2 @@
1
+ var pe=Object.defineProperty;var m=(i,e)=>pe(i,"name",{value:e,configurable:!0});import{cG as E,a as I,c as oe,_ as B,k as me,cu as fe,l as ge,h as W,s as ve,u as te,d as ae,m as he}from"./index-BFHZsBkN.js";import{b as re,E as V,a as be,bx as F,cM as O,cN as N,j as C,d,by as p,m as ye,k as b,e as r,G as ee,c as g,q as _,u,p as we,d3 as _e,cw as $e,z as $,w as G,d2 as ke,eE as Me,r as x,A as j,F as Ue,f as ne,o as xe,bg as Se,dc as Ce,cd as Ie,s as Z}from"./vendor-other-B8t_Wf2K.js";import{i as Be,y as Fe,e as ie,a as Ve}from"./vendor-primevue-DeKsC2uk.js";import{u as de}from"./vendor-vue-DaLZjKA7.js";function D(){const i=re({get supportsPreviewMetadata(){return I.getServerFeature("supports_preview_metadata")},get maxUploadSize(){return I.getServerFeature("max_upload_size")},get supportsManagerV4(){return I.getServerFeature("extension.manager.supports_v4")},get modelUploadButtonEnabled(){return E.value.model_upload_button_enabled??I.getServerFeature("model_upload_button_enabled",!1)},get assetDeletionEnabled(){return E.value.asset_deletion_enabled??I.getServerFeature("asset_deletion_enabled",!1)},get assetRenameEnabled(){return E.value.asset_rename_enabled??I.getServerFeature("asset_rename_enabled",!1)},get privateModelsEnabled(){return E.value.private_models_enabled??I.getServerFeature("private_models_enabled",!1)},get onboardingSurveyEnabled(){return E.value.onboarding_survey_enabled??I.getServerFeature("onboarding_survey_enabled",!0)},get huggingfaceModelImportEnabled(){return E.value.huggingface_model_import_enabled??I.getServerFeature("huggingface_model_import_enabled",!1)},get asyncModelUploadEnabled(){return E.value.async_model_upload_enabled??I.getServerFeature("async_model_upload_enabled",!1)}}),e=m((n,s)=>V(()=>I.getServerFeature(n,s)),"featureFlag");return{flags:be(i),featureFlag:e}}m(D,"useFeatureFlags");const Le={class:"flex items-center gap-2 text-sm"},je={key:0,class:"text-base-foreground"},Ae={key:1,class:"text-base-foreground"},Ee={class:"truncate"},De={key:0,class:"icon-[lucide--check] text-base-foreground"},ze=F({inheritAttrs:!1,__name:"SingleSelect",props:O({label:{},options:{},listMaxHeight:{default:"28rem"},popoverMinWidth:{},popoverMaxWidth:{}},{modelValue:{required:!0},modelModifiers:{}}),emits:["update:modelValue"],setup(i){const e=N(i,"modelValue"),{t:n}=de(),s=m(o=>{if(o==null||!i.options)return i.label??"";const a=i.options.find(l=>l.value===o);return a?a.name:i.label??""},"getLabel"),t=V(()=>{if(!i.popoverMinWidth&&!i.popoverMaxWidth)return;const o=[];return i.popoverMinWidth&&o.push(`min-width: ${i.popoverMinWidth}`),i.popoverMaxWidth&&o.push(`max-width: ${i.popoverMaxWidth}`),o.join("; ")});return(o,a)=>(d(),C(p(Be),ye({modelValue:e.value,"onUpdate:modelValue":a[0]||(a[0]=l=>e.value=l)},o.$attrs,{options:o.options,"option-label":"name","option-value":"value",unstyled:"",pt:{root:m(({props:l})=>({class:["h-10 relative inline-flex cursor-pointer select-none items-center","rounded-lg","bg-secondary-background text-base-foreground","border-[2.5px] border-solid border-transparent","transition-all duration-200 ease-in-out","focus-within:border-node-component-border",{"opacity-60 cursor-default":l.disabled}]}),"root"),label:{class:"flex-1 flex items-center whitespace-nowrap pl-4 py-2 outline-hidden"},dropdown:{class:"flex shrink-0 items-center justify-center px-3 py-2"},overlay:{class:p(oe)("mt-2 p-2 rounded-lg","bg-base-background text-base-foreground","border border-solid border-border-default")},listContainer:m(()=>({style:`max-height: min(${o.listMaxHeight}, 50vh)`,class:"scrollbar-custom"}),"listContainer"),list:{class:"flex flex-col gap-0 p-0 m-0 list-none border-none text-sm"},option:m(({context:l})=>({class:p(oe)("flex items-center justify-between gap-3 px-2 py-3 rounded","hover:bg-secondary-background-hover",l.focused&&"bg-secondary-background-hover",l.selected&&"bg-secondary-background-selected hover:bg-secondary-background-selected")}),"option"),optionLabel:{class:"truncate"},optionGroupLabel:{class:"px-3 py-2 text-xs uppercase tracking-wide text-muted-foreground"},emptyMessage:{class:"px-3 py-2 text-sm text-muted-foreground"}},"aria-label":o.label||p(n)("g.singleSelectDropdown"),role:"combobox","aria-expanded":!1,"aria-haspopup":"listbox",tabindex:0}),{value:b(l=>[r("div",Le,[we(o.$slots,"icon"),l.value!==null&&l.value!==void 0?(d(),g("span",je,u(s(l.value)),1)):(d(),g("span",Ae,u(o.label),1))])]),dropdownicon:b(()=>a[1]||(a[1]=[r("i",{class:"icon-[lucide--chevron-down] text-muted-foreground"},null,-1)])),option:b(({option:l,selected:c})=>[r("div",{class:"flex w-full items-center justify-between gap-3",style:ee(t.value)},[r("span",Ee,u(l.name),1),c?(d(),g("i",De)):_("",!0)],4)]),_:3},16,["modelValue","options","pt","aria-label"]))}});function Re(i){const e={loras:"LoRA",ipadapter:"IP-Adapter",sams:"SAM",clip_vision:"CLIP Vision",animatediff_motion_lora:"AnimateDiff Motion LoRA",animatediff_models:"AnimateDiff Model",vae:"VAE",sam2:"SAM 2",controlnet:"ControlNet",gligen:"GLIGEN"};return e[i]?e[i]:i.split("_").map(n=>n.charAt(0).toUpperCase()+n.slice(1)).join(" ")}m(Re,"formatDisplayName");const Te=["nlf"],ue=_e(()=>{const{state:i,isLoading:e,error:n,execute:s}=$e(async()=>(await I.getModelFolders()).filter(o=>!Te.includes(o.name)).map(o=>({name:Re(o.name),value:o.name})).sort((o,a)=>o.name.localeCompare(a.name)),[],{immediate:!1,onError:m(t=>{console.error("Failed to fetch model types:",t)},"onError")});return{modelTypes:i,isLoading:e,error:n,fetchModelTypes:s}}),He={class:"flex flex-col gap-4 text-sm text-muted-foreground"},Pe={class:"flex flex-col gap-2"},We={class:"m-0"},qe={class:"flex items-center gap-3 rounded-lg bg-secondary-background px-4 py-2"},Oe=["src","alt"],Ne={class:"m-0 min-w-0 flex-1 truncate text-base-foreground"},Ge={class:"flex flex-col gap-2"},Ke={class:"flex items-center gap-2"},Ye={class:"text-muted-foreground"},Je=F({__name:"UploadModelConfirmation",props:O({metadata:{},previewImage:{}},{modelValue:{},modelModifiers:{}}),emits:["update:modelValue"],setup(i){const e=N(i,"modelValue"),{modelTypes:n,isLoading:s}=ue();return(t,o)=>(d(),g("div",He,[r("div",Pe,[r("p",We,u(t.$t("assetBrowser.modelAssociatedWithLink")),1),r("div",qe,[t.previewImage?(d(),g("img",{key:0,src:t.previewImage,alt:t.metadata?.filename||t.metadata?.name||"Model preview",class:"size-14 flex-shrink-0 rounded object-cover"},null,8,Oe)):_("",!0),r("p",Ne,u(t.metadata?.filename||t.metadata?.name),1)])]),r("div",Ge,[r("div",Ke,[r("label",null,u(t.$t("assetBrowser.modelTypeSelectorLabel")),1),o[1]||(o[1]=r("i",{class:"icon-[lucide--circle-question-mark] text-muted-foreground"},null,-1)),r("span",Ye,u(t.$t("assetBrowser.notSureLeaveAsIs")),1)]),$(ze,{modelValue:e.value,"onUpdate:modelValue":o[0]||(o[0]=a=>e.value=a),label:p(s)?t.$t("g.loading"):t.$t("assetBrowser.modelTypeSelectorPlaceholder"),options:p(n),disabled:p(s),"data-attr":"upload-model-step2-type-selector"},null,8,["modelValue","label","options","disabled"])])]))}}),Qe={class:"relative"},Xe=["aria-label","src"],le=F({__name:"VideoHelpDialog",props:O({videoUrl:{},ariaLabel:{default:"Help video"}},{modelValue:{type:Boolean,required:!0},modelModifiers:{}}),emits:["update:modelValue"],setup(i){const e=N(i,"modelValue"),n=m(s=>{s.key==="Escape"&&(s.stopImmediatePropagation(),s.stopPropagation(),s.preventDefault(),e.value=!1)},"handleEscapeKey");return G(e,s=>{if(s){const t=ke(document,"keydown",n,{capture:!0});Me(t)}},{immediate:!0}),(s,t)=>(d(),C(p(Fe),{visible:e.value,"onUpdate:visible":t[1]||(t[1]=o=>e.value=o),modal:"",closable:!1,"close-on-escape":!1,"dismissable-mask":!0,pt:{root:{class:"video-help-dialog"},header:{class:"!hidden"},content:{class:"!p-0"},mask:{class:"!bg-black/70"}},style:{width:"90vw"}},{default:b(()=>[r("div",Qe,[$(B,{variant:"textonly",size:"icon",class:"absolute top-4 right-6 z-10","aria-label":s.$t("g.close"),onClick:t[0]||(t[0]=o=>e.value=!1)},{default:b(()=>t[2]||(t[2]=[r("i",{class:"pi pi-times text-sm"},null,-1)])),_:1},8,["aria-label"]),r("video",{autoplay:"",muted:"",loop:"","aria-label":s.ariaLabel,class:"w-full rounded-lg",src:s.videoUrl},u(s.$t("g.videoFailedToLoad")),9,Xe)])]),_:1},8,["visible"]))}}),Ze={class:"flex justify-end gap-2 w-full"},et={key:0,class:"mr-auto flex items-center gap-2"},tt={key:4},at={key:0,class:"icon-[lucide--loader-circle] animate-spin"},st={key:0,class:"icon-[lucide--loader-circle] animate-spin"},ot=F({__name:"UploadModelFooter",props:{currentStep:{},isFetchingMetadata:{type:Boolean},isUploading:{type:Boolean},canFetchMetadata:{type:Boolean},canUploadModel:{type:Boolean},uploadStatus:{}},emits:["back","fetchMetadata","upload","close","importAnother"],setup(i,{emit:e}){const{flags:n}=D(),s=x(!1),t=x(!1),o=e;return(a,l)=>(d(),g("div",Ze,[a.currentStep===1&&p(n).huggingfaceModelImportEnabled?(d(),g("div",et,[l[11]||(l[11]=r("i",{class:"icon-[lucide--circle-question-mark] text-muted-foreground"},null,-1)),$(B,{variant:"muted-textonly",size:"sm","data-attr":"upload-model-step1-help-civitai",onClick:l[0]||(l[0]=c=>s.value=!0)},{default:b(()=>[j(u(a.$t("assetBrowser.providerCivitai")),1)]),_:1}),$(B,{variant:"muted-textonly",size:"sm","data-attr":"upload-model-step1-help-huggingface",onClick:l[1]||(l[1]=c=>t.value=!0)},{default:b(()=>[j(u(a.$t("assetBrowser.providerHuggingFace")),1)]),_:1})])):a.currentStep===1?(d(),C(B,{key:1,variant:"muted-textonly",size:"lg",class:"mr-auto underline","data-attr":"upload-model-step1-help-link",onClick:l[2]||(l[2]=c=>s.value=!0)},{default:b(()=>[l[12]||(l[12]=r("i",{class:"icon-[lucide--circle-question-mark]"},null,-1)),r("span",null,u(a.$t("assetBrowser.uploadModelHowDoIFindThis")),1)]),_:1})):_("",!0),a.currentStep===1?(d(),C(B,{key:2,variant:"muted-textonly",size:"lg","data-attr":"upload-model-step1-cancel-button",disabled:a.isFetchingMetadata||a.isUploading,onClick:l[3]||(l[3]=c=>o("close"))},{default:b(()=>[j(u(a.$t("g.cancel")),1)]),_:1},8,["disabled"])):_("",!0),a.currentStep!==1&&a.currentStep!==3?(d(),C(B,{key:3,variant:"muted-textonly",size:"lg","data-attr":`upload-model-step${a.currentStep}-back-button`,disabled:a.isFetchingMetadata||a.isUploading,onClick:l[4]||(l[4]=c=>o("back"))},{default:b(()=>[j(u(a.$t("g.back")),1)]),_:1},8,["data-attr","disabled"])):(d(),g("span",tt)),a.currentStep===1?(d(),C(B,{key:5,variant:"secondary",size:"lg","data-attr":"upload-model-step1-continue-button",disabled:!a.canFetchMetadata||a.isFetchingMetadata,onClick:l[5]||(l[5]=c=>o("fetchMetadata"))},{default:b(()=>[a.isFetchingMetadata?(d(),g("i",at)):_("",!0),r("span",null,u(a.$t("g.continue")),1)]),_:1},8,["disabled"])):a.currentStep===2?(d(),C(B,{key:6,variant:"secondary",size:"lg","data-attr":"upload-model-step2-confirm-button",disabled:!a.canUploadModel||a.isUploading,onClick:l[6]||(l[6]=c=>o("upload"))},{default:b(()=>[a.isUploading?(d(),g("i",st)):_("",!0),r("span",null,u(a.$t("assetBrowser.upload")),1)]),_:1},8,["disabled"])):a.currentStep===3&&(a.uploadStatus==="success"||a.uploadStatus==="processing")?(d(),g(Ue,{key:7},[$(B,{variant:"muted-textonly",size:"lg","data-attr":"upload-model-step3-import-another-button",onClick:l[7]||(l[7]=c=>o("importAnother"))},{default:b(()=>[j(u(a.$t("assetBrowser.importAnother")),1)]),_:1}),$(B,{variant:"secondary",size:"lg","data-attr":"upload-model-step3-finish-button",onClick:l[8]||(l[8]=c=>o("close"))},{default:b(()=>[j(u(a.uploadStatus==="processing"?a.$t("g.close"):a.$t("assetBrowser.finish")),1)]),_:1})],64)):_("",!0),$(le,{modelValue:s.value,"onUpdate:modelValue":l[9]||(l[9]=c=>s.value=c),"video-url":"https://media.comfy.org/compressed_768/civitai_howto.webm","aria-label":a.$t("assetBrowser.uploadModelHelpVideo")},null,8,["modelValue","aria-label"]),$(le,{modelValue:t.value,"onUpdate:modelValue":l[10]||(l[10]=c=>t.value=c),"video-url":"https://media.comfy.org/byom/huggingfacehowto.mp4","aria-label":a.$t("assetBrowser.uploadModelHelpVideo")},null,8,["modelValue","aria-label"])]))}}),lt={class:"flex flex-1 flex-col gap-6 text-sm text-muted-foreground"},rt={key:0,class:"flex flex-col gap-2"},nt={class:"m-0 font-bold"},it={class:"m-0"},dt={class:"flex flex-row items-center gap-3 rounded-lg bg-modal-card-background p-4"},ut=["src","alt"],ct={class:"flex min-w-0 flex-1 flex-col items-start justify-center gap-1"},pt={class:"m-0 w-full truncate text-base-foreground"},mt={class:"m-0 text-sm text-muted"},ft={key:1,class:"flex flex-col gap-2"},gt={class:"m-0 font-bold"},vt={class:"m-0"},ht={class:"flex flex-row items-center gap-3 rounded-lg bg-modal-card-background p-4"},bt=["src","alt"],yt={class:"flex min-w-0 flex-1 flex-col items-start justify-center gap-1"},wt={class:"m-0 w-full truncate text-base-foreground"},_t={class:"m-0 text-sm text-muted"},$t={key:2,class:"flex flex-1 flex-col items-center justify-center gap-6"},kt={class:"text-center"},Mt={class:"m-0 text-sm font-bold"},Ut={key:0,class:"text-sm text-muted mb-0"},xt=F({__name:"UploadModelProgress",props:{result:{},error:{},metadata:{},modelType:{},previewImage:{}},setup(i){return(e,n)=>(d(),g("div",lt,[e.result==="processing"?(d(),g("div",rt,[r("p",nt,u(e.$t("assetBrowser.processingModel")),1),r("p",it,u(e.$t("assetBrowser.processingModelDescription")),1),r("div",dt,[e.previewImage?(d(),g("img",{key:0,src:e.previewImage,alt:e.metadata?.filename||e.metadata?.name||"Model preview",class:"size-14 flex-shrink-0 rounded object-cover"},null,8,ut)):_("",!0),r("div",ct,[r("p",pt,u(e.metadata?.filename||e.metadata?.name),1),r("p",mt,u(e.modelType),1)])])])):e.result==="success"?(d(),g("div",ft,[r("p",gt,u(e.$t("assetBrowser.modelUploaded")),1),r("p",vt,u(e.$t("assetBrowser.findInLibrary",{type:e.modelType})),1),r("div",ht,[e.previewImage?(d(),g("img",{key:0,src:e.previewImage,alt:e.metadata?.filename||e.metadata?.name||"Model preview",class:"size-14 flex-shrink-0 rounded object-cover"},null,8,bt)):_("",!0),r("div",yt,[r("p",wt,u(e.metadata?.filename||e.metadata?.name),1),r("p",_t,u(e.modelType),1)])])])):e.result==="error"?(d(),g("div",$t,[n[0]||(n[0]=r("i",{class:"icon-[lucide--x-circle] text-6xl text-error"},null,-1)),r("div",kt,[r("p",Mt,u(e.$t("assetBrowser.uploadFailed")),1),e.error?(d(),g("p",Ut,u(e.error),1)):_("",!0)])])):_("",!0)]))}}),q={type:"civitai",name:"Civitai",hostnames:["civitai.com"]},ce={type:"huggingface",name:"Hugging Face",hostnames:["huggingface.co"]};function se(i,e){try{const n=new URL(i).hostname.toLowerCase();return e.hostnames.some(s=>n===s||n.endsWith(`.${s}`))}catch{return!1}}m(se,"validateSourceUrl");const St={class:"flex flex-col justify-between h-full gap-6 text-sm"},Ct={class:"flex flex-col gap-6"},It={class:"flex flex-col gap-2"},Bt={class:"m-0 text-foreground"},Ft={class:"m-0"},Vt={class:"m-0 text-muted-foreground"},Lt={class:"inline-flex items-center gap-1 flex-wrap mt-2"},jt={class:"inline-flex items-center gap-1"},At=["alt"],Et={class:"inline-flex items-center gap-1"},Dt=["alt"],zt={class:"flex flex-col gap-2"},Rt={class:"relative"},Tt={key:0,class:"icon-[lucide--circle-check-big] absolute top-1/2 right-3 size-5 -translate-y-1/2 text-green-500"},Ht={key:0,class:"text-sm text-error"},Pt={key:1,class:"text-foreground"},Wt={class:"font-bold italic"},qt={class:"text-sm text-muted"},Ot="/assets/images/civitai.svg",Nt="https://civitai.com/models",Gt="/assets/images/hf-logo.svg",Kt="https://huggingface.co",Yt=F({__name:"UploadModelUrlInput",props:{modelValue:{},error:{}},emits:["update:modelValue"],setup(i,{emit:e}){const{flags:n}=D(),s=i,t=e,o=V({get:m(()=>s.modelValue,"get"),set:m(c=>t("update:modelValue",c),"set")}),a=[q,ce],l=V(()=>{const c=o.value.trim();return c?a.some(y=>se(c,y)):!1});return(c,y)=>{const k=ne("i18n-t");return d(),g("div",St,[r("div",Ct,[r("div",It,[r("p",Bt,u(c.$t("assetBrowser.uploadModelDescription1Generic")),1),r("div",Ft,[r("p",Vt,u(c.$t("assetBrowser.uploadModelDescription2Generic")),1),r("span",Lt,[r("span",jt,[r("img",{src:Ot,alt:c.$t("assetBrowser.providerCivitai"),class:"w-4 h-4"},null,8,At),r("a",{href:Nt,target:"_blank",rel:"noopener noreferrer",class:"text-muted-foreground underline"},u(c.$t("assetBrowser.providerCivitai")),1),y[1]||(y[1]=r("span",null,",",-1))]),r("span",Et,[r("img",{src:Gt,alt:c.$t("assetBrowser.providerHuggingFace"),class:"w-4 h-4"},null,8,Dt),r("a",{href:Kt,target:"_blank",rel:"noopener noreferrer",class:"text-muted-foreground underline"},u(c.$t("assetBrowser.providerHuggingFace")),1)])])])]),r("div",zt,[r("div",Rt,[$(p(ie),{modelValue:o.value,"onUpdate:modelValue":y[0]||(y[0]=h=>o.value=h),autofocus:"",placeholder:c.$t("assetBrowser.genericLinkPlaceholder"),class:"w-full border-0 bg-secondary-background p-4 pr-10","data-attr":"upload-model-step1-url-input"},null,8,["modelValue","placeholder"]),l.value?(d(),g("i",Tt)):_("",!0)]),c.error?(d(),g("p",Ht,u(c.error),1)):p(n).asyncModelUploadEnabled?_("",!0):(d(),g("p",Pt,[$(k,{keypath:"assetBrowser.maxFileSize",tag:"span"},{size:b(()=>[r("span",Wt,u(c.$t("assetBrowser.maxFileSizeValue")),1)]),_:1})]))])]),r("div",qt,u(c.$t("assetBrowser.uploadModelHelpFooterText")),1)])}}}),Jt={class:"flex flex-col gap-6 text-sm text-muted-foreground"},Qt={class:"flex flex-col gap-2"},Xt={class:"m-0"},Zt={class:"list-disc space-y-1 pl-5 mt-0"},ea={href:"https://civitai.com/models",target:"_blank",class:"text-muted-foreground underline"},ta={key:0},aa={class:"font-bold italic"},sa={class:"flex flex-col gap-2"},oa={class:"font-bold italic"},la={class:"relative"},ra={key:0,class:"icon-[lucide--circle-check-big] absolute top-1/2 right-3 size-5 -translate-y-1/2 text-green-500"},na={key:0,class:"text-sm text-error"},ia={href:"https://civitai.com/models/10706/luisap-z-image-and-qwen-pixel-art-refiner?modelVersionId=2225295",target:"_blank",class:"text-muted-foreground underline"},da=F({__name:"UploadModelUrlInputCivitai",props:O({error:{}},{modelValue:{required:!0},modelModifiers:{}}),emits:["update:modelValue"],setup(i){const{flags:e}=D(),n=N(i,"modelValue"),s=V(()=>{const t=n.value.trim();return t?se(t,q):!1});return(t,o)=>{const a=ne("i18n-t");return d(),g("div",Jt,[r("div",Qt,[r("p",Xt,u(t.$t("assetBrowser.uploadModelDescription1")),1),r("ul",Zt,[r("li",null,[$(a,{keypath:"assetBrowser.uploadModelDescription2",tag:"span"},{link:b(()=>[r("a",ea,u(t.$t("assetBrowser.uploadModelDescription2Link")),1)]),_:1})]),p(e).asyncModelUploadEnabled?_("",!0):(d(),g("li",ta,[$(a,{keypath:"assetBrowser.uploadModelDescription3",tag:"span"},{size:b(()=>[r("span",aa,u(t.$t("assetBrowser.maxFileSizeValue")),1)]),_:1})]))])]),r("div",sa,[$(a,{keypath:"assetBrowser.civitaiLinkLabel",tag:"label",class:"mb-0"},{download:b(()=>[r("span",oa,u(t.$t("assetBrowser.civitaiLinkLabelDownload")),1)]),_:1}),r("div",la,[$(p(ie),{modelValue:n.value,"onUpdate:modelValue":o[0]||(o[0]=l=>n.value=l),autofocus:"",placeholder:t.$t("assetBrowser.civitaiLinkPlaceholder"),class:"w-full border-0 bg-secondary-background p-4 pr-10","data-attr":"upload-model-step1-url-input"},null,8,["modelValue","placeholder"]),s.value?(d(),g("i",ra)):_("",!0)]),t.error?(d(),g("p",na,u(t.error),1)):(d(),C(a,{key:1,keypath:"assetBrowser.civitaiLinkExample",tag:"p",class:"text-sm"},{example:b(()=>[r("strong",null,u(t.$t("assetBrowser.civitaiLinkExampleStrong")),1)]),link:b(()=>[r("a",ia,u(t.$t("assetBrowser.civitaiLinkExampleUrl")),1)]),_:1}))])])}}});function ua(i){const{t:e}=de(),n=me(),s=fe(),t=ge(),{flags:o}=D(),a=x(1),l=x(!1),c=x(!1),y=x(),k=x(""),h=x({url:"",name:"",tags:[]}),v=x(),M=o.huggingfaceModelImportEnabled?[q,ce]:[q],A=V(()=>{const U=h.value.url.trim();return U?M.find(w=>se(U,w))??null:null});G(()=>h.value.url,()=>{k.value=""});const T=V(()=>h.value.url.trim().length>0),H=V(()=>!!v.value);async function K(){if(!T.value)return;let U=h.value.url.trim();try{U=new URL(encodeURI(U)).toString()}catch{}if(h.value.url=U,!A.value){const f=M.map(S=>S.name).join(", ");k.value=e("assetBrowser.unsupportedUrlSource",{sources:f});return}l.value=!0;try{const f=await W.getAssetMetadata(h.value.url);if(f.filename)try{f.filename=decodeURIComponent(f.filename)}catch{}if(f.name)try{f.name=decodeURIComponent(f.name)}catch{}if(h.value.metadata=f,h.value.name=f.filename||f.name||"",h.value.previewImage=f.preview_image,f.tags&&f.tags.length>0){h.value.tags=f.tags;const S=f.tags.find(z=>i.value.some(R=>R.value===z));S&&(v.value=S)}a.value=2}catch(f){console.error("Failed to retrieve metadata:",f),k.value=f instanceof Error?f.message:ve("assetBrowser.uploadModelFailedToRetrieveMetadata","Failed to retrieve metadata. Please check the link and try again."),a.value=1}finally{l.value=!1}}m(K,"fetchMetadata");async function Y(U){if(h.value.previewImage)try{const w=U.split(".")[0];let f="png";const S=h.value.previewImage.match(/^data:image\/([^;]+);/);return S&&(f=S[1]==="jpeg"?"jpg":S[1]),(await W.uploadAssetFromBase64({data:h.value.previewImage,name:`${w}_preview.${f}`,tags:["preview"]})).id}catch(w){console.error("Failed to upload preview image:",w);return}}m(Y,"uploadPreviewImage");async function P(){if(!v.value)return;const U=t.getAllNodeProviders(v.value);(await Promise.allSettled(U.map(f=>n.updateModelsForNodeType(f.nodeDef.name)))).forEach((f,S)=>{f.status==="rejected"&&console.error(`Failed to refresh ${U[S].nodeDef.name}:`,f.reason)})}m(P,"refreshModelCaches");async function J(){if(!H.value)return!1;const U=A.value;if(!U)return k.value=e("assetBrowser.noValidSourceDetected"),!1;c.value=!0;try{const w=v.value?["models",v.value]:["models"],f=h.value.metadata?.filename||h.value.metadata?.name||"model",S=await Y(f),z={source:U.type,source_url:h.value.url,model_type:v.value};if(o.asyncModelUploadEnabled){const R=await W.uploadAssetAsync({source_url:h.value.url,tags:w,user_metadata:z,preview_id:S});R.type==="async"&&R.task.status!=="completed"?(v.value&&s.trackDownload(R.task.task_id,v.value,f),y.value="processing"):(y.value="success",await P()),a.value=3}else await W.uploadAssetFromUrl({url:h.value.url,name:f,tags:w,user_metadata:z,preview_id:S}),y.value="success",await P(),a.value=3}catch(w){console.error("Failed to upload asset:",w),y.value="error",k.value=w instanceof Error?w.message:"Failed to upload model",a.value=3}finally{c.value=!1}return y.value!=="error"}m(J,"uploadModel");function Q(){a.value>1&&(a.value=a.value-1)}m(Q,"goToPreviousStep");function X(){a.value=1,l.value=!1,c.value=!1,y.value=void 0,k.value="",h.value={url:"",name:"",tags:[]},v.value=void 0}return m(X,"resetWizard"),{currentStep:a,isFetchingMetadata:l,isUploading:c,uploadStatus:y,uploadError:k,wizardData:h,selectedModelType:v,canFetchMetadata:T,canUploadModel:H,detectedSource:A,fetchMetadata:K,uploadModel:J,goToPreviousStep:Q,resetWizard:X}}m(ua,"useUploadModelWizard");const ca={class:"upload-model-dialog flex flex-col gap-6 border-t border-border-default p-4 pt-6"},pa={class:"min-h-0 flex-auto basis-0 overflow-y-auto"},ma=F({__name:"UploadModelDialog",emits:["upload-success"],setup(i,{emit:e}){const{flags:n}=D(),s=te(),{modelTypes:t,fetchModelTypes:o}=ue(),a=e,{currentStep:l,isFetchingMetadata:c,isUploading:y,uploadStatus:k,uploadError:h,wizardData:v,selectedModelType:M,canFetchMetadata:A,canUploadModel:T,fetchMetadata:H,uploadModel:K,goToPreviousStep:Y,resetWizard:P}=ua(t);async function J(){await H()}m(J,"handleFetchMetadata");async function Q(){await K()&&a("upload-success")}m(Q,"handleUploadModel");function X(){s.closeDialog({key:"upload-model"})}return m(X,"handleClose"),xe(()=>{o()}),(U,w)=>(d(),g("div",ca,[r("div",pa,[p(l)===1&&p(n).huggingfaceModelImportEnabled?(d(),C(Yt,{key:0,modelValue:p(v).url,"onUpdate:modelValue":w[0]||(w[0]=f=>p(v).url=f),error:p(h)},null,8,["modelValue","error"])):p(l)===1?(d(),C(da,{key:1,modelValue:p(v).url,"onUpdate:modelValue":w[1]||(w[1]=f=>p(v).url=f),error:p(h)},null,8,["modelValue","error"])):p(l)===2?(d(),C(Je,{key:2,modelValue:p(M),"onUpdate:modelValue":w[2]||(w[2]=f=>Se(M)?M.value=f:null),metadata:p(v).metadata,"preview-image":p(v).previewImage},null,8,["modelValue","metadata","preview-image"])):p(l)===3&&p(k)!=null?(d(),C(xt,{key:3,result:p(k),error:p(h),metadata:p(v).metadata,"model-type":p(M),"preview-image":p(v).previewImage},null,8,["result","error","metadata","model-type","preview-image"])):_("",!0)]),$(ot,{class:"flex-shrink-0","current-step":p(l),"is-fetching-metadata":p(c),"is-uploading":p(y),"can-fetch-metadata":p(A),"can-upload-model":p(T),"upload-status":p(k),onBack:p(Y),onFetchMetadata:J,onUpload:Q,onClose:X,onImportAnother:p(P)},null,8,["current-step","is-fetching-metadata","is-uploading","can-fetch-metadata","can-upload-model","upload-status","onBack","onImportAnother"])]))}}),fa=ae(ma,[["__scopeId","data-v-f4fd265e"]]),ga=""+new URL("images/civitai.svg",import.meta.url).href,va={class:"flex items-center gap-2 p-4 font-bold"},ha={key:0,src:ga,class:"size-4"},ba={class:"rounded-full bg-white px-1.5 py-0 text-xxs font-inter font-semibold uppercase text-black"},ya=F({__name:"UploadModelDialogHeader",setup(i){const{flags:e}=D(),n=V(()=>e.huggingfaceModelImportEnabled?"assetBrowser.uploadModelGeneric":"assetBrowser.uploadModelFromCivitai");return(s,t)=>(d(),g("div",va,[p(e).huggingfaceModelImportEnabled?_("",!0):(d(),g("img",ha)),r("span",null,u(s.$t(n.value)),1),r("span",ba,u(s.$t("g.beta")),1)]))}}),wa={},_a={class:"flex flex-1 flex-col items-center justify-center text-base text-muted-foreground"},$a={class:"m-0 max-w-md"};function ka(i,e){return d(),g("div",_a,[r("p",$a,u(i.$t("assetBrowser.upgradeFeatureDescription")),1)])}m(ka,"_sfc_render$1");const Ma=ae(wa,[["render",ka]]),Ua={class:"flex flex-wrap justify-end gap-2 w-full"},xa={href:"https://blog.comfy.org/p/comfy-cloud-new-features-and-pricing",target:"_blank",rel:"noopener noreferrer",class:"text-muted-foreground mr-auto underline flex items-center gap-2"},Sa=F({__name:"UploadModelUpgradeModalFooter",emits:["close","subscribe"],setup(i,{emit:e}){const n=e;return(s,t)=>(d(),g("div",Ua,[r("a",xa,[t[2]||(t[2]=r("i",{class:"icon-[lucide--external-link]"},null,-1)),r("span",null,u(s.$t("g.learnMore")),1)]),$(B,{variant:"textonly",onClick:t[0]||(t[0]=o=>n("close"))},{default:b(()=>[j(u(s.$t("g.close")),1)]),_:1}),$(B,{variant:"secondary",onClick:t[1]||(t[1]=o=>n("subscribe"))},{default:b(()=>[j(u(s.$t("subscription.required.subscribe")),1)]),_:1})]))}}),Ca={class:"flex flex-col justify-between gap-10 p-4 border-t border-border-default w-auto max-w-[min(500px,90vw)]"},Ia=F({__name:"UploadModelUpgradeModal",setup(i){const e=te(),{showSubscriptionDialog:n}=he();function s(){e.closeDialog({key:"upload-model-upgrade"})}m(s,"handleClose");function t(){n()}return m(t,"handleSubscribe"),(o,a)=>(d(),g("div",Ca,[$(Ma),$(Sa,{onClose:s,onSubscribe:t})]))}}),Ba={},Fa={class:"flex items-center gap-2 p-4 font-bold"};function Va(i,e){return d(),g("div",Fa,[r("span",null,u(i.$t("assetBrowser.upgradeToUnlockFeature")),1)])}m(Va,"_sfc_render");const La=ae(Ba,[["render",Va]]);function Na(i){const e=te(),{flags:n}=D(),s=V(()=>n.modelUploadButtonEnabled);function t(){n.privateModelsEnabled?e.showDialog({key:"upload-model",headerComponent:ya,component:fa,props:{onUploadSuccess:m(async()=>{await i?.()},"onUploadSuccess")},dialogComponentProps:{pt:{header:"py-0! pl-0!",content:"p-0! overflow-y-hidden!"}}}):e.showDialog({key:"upload-model-upgrade",headerComponent:La,component:Ia,dialogComponentProps:{pt:{header:"py-0! pl-0!",content:"p-0! overflow-y-hidden!"}}})}return m(t,"showUploadDialog"),{isUploadButtonEnabled:s,showUploadDialog:t}}m(Na,"useModelUpload");const ja=""+new URL("images/default-template.png",import.meta.url).href;function Aa(i,e,n={}){const{immediate:s=!0,...t}=n,o=typeof window<"u"&&"IntersectionObserver"in window,a=x(!1);let l=null;const c=m(()=>{l&&(l.disconnect(),l=null)},"cleanup"),y=m(()=>{c(),!(!o||!i.value)&&(l=new IntersectionObserver(h=>{a.value=h.some(v=>v.isIntersecting),e(h,l)},t),l.observe(i.value))},"observe"),k=m(()=>{l&&i.value&&l.unobserve(i.value)},"unobserve");return s&&G(i,y,{immediate:!0,flush:"post"}),Ce(c),{isSupported:o,isIntersecting:a,observe:y,unobserve:k,cleanup:c}}m(Aa,"useIntersectionObserver");class Ea{static{m(this,"MediaCacheService")}cache=re(new Map);maxSize;maxAge;cleanupInterval=null;urlRefCount=new Map;constructor(e={}){this.maxSize=e.maxSize??100,this.maxAge=e.maxAge??1800*1e3,this.startCleanupInterval()}startCleanupInterval(){this.cleanupInterval=window.setInterval(()=>{this.cleanup()},300*1e3)}cleanup(){const e=Date.now(),n=[];for(const[s,t]of Array.from(this.cache.entries()))e-t.lastAccessed>this.maxAge&&(t.objectUrl?(this.urlRefCount.get(t.objectUrl)||0)===0&&(URL.revokeObjectURL(t.objectUrl),this.urlRefCount.delete(t.objectUrl),n.push(s)):n.push(s));if(n.forEach(s=>this.cache.delete(s)),this.cache.size>this.maxSize){const s=Array.from(this.cache.entries());s.sort((a,l)=>a[1].lastAccessed-l[1].lastAccessed);let t=0;const o=this.cache.size-this.maxSize;for(const[a,l]of s){if(t>=o)break;l.objectUrl?(this.urlRefCount.get(l.objectUrl)||0)===0&&(URL.revokeObjectURL(l.objectUrl),this.urlRefCount.delete(l.objectUrl),this.cache.delete(a),t++):(this.cache.delete(a),t++)}}}async getCachedMedia(e){let n=this.cache.get(e);if(n)return n.lastAccessed=Date.now(),n;n={src:e,isLoading:!0,lastAccessed:Date.now()},this.cache.set(e,n);try{const s=await fetch(e,{cache:"force-cache"});if(!s.ok)throw new Error(`Failed to fetch: ${s.status}`);const t=await s.blob(),o=URL.createObjectURL(t),a={src:e,blob:t,objectUrl:o,isLoading:!1,lastAccessed:Date.now()};return this.cache.set(e,a),a}catch(s){console.warn("Failed to cache media:",e,s);const t={src:e,error:!0,isLoading:!1,lastAccessed:Date.now()};return this.cache.set(e,t),t}}acquireUrl(e){const n=this.cache.get(e);if(n?.objectUrl){const s=this.urlRefCount.get(n.objectUrl)||0;return this.urlRefCount.set(n.objectUrl,s+1),n.objectUrl}}releaseUrl(e){const n=this.cache.get(e);if(n?.objectUrl){const s=(this.urlRefCount.get(n.objectUrl)||1)-1;s<=0?(URL.revokeObjectURL(n.objectUrl),this.urlRefCount.delete(n.objectUrl),this.cache.delete(e)):this.urlRefCount.set(n.objectUrl,s)}}clearCache(){for(const e of Array.from(this.cache.values()))e.objectUrl&&URL.revokeObjectURL(e.objectUrl);this.cache.clear(),this.urlRefCount.clear()}destroy(){this.cleanupInterval&&(clearInterval(this.cleanupInterval),this.cleanupInterval=null),this.clearCache()}}let L=null;function Da(i){return L||(L=new Ea(i)),{getCachedMedia:m(o=>L.getCachedMedia(o),"getCachedMedia"),clearCache:m(()=>L.clearCache(),"clearCache"),acquireUrl:m(o=>L.acquireUrl(o),"acquireUrl"),releaseUrl:m(o=>L.releaseUrl(o),"releaseUrl"),cache:L.cache}}m(Da,"useMediaCache");typeof window<"u"&&window.addEventListener("beforeunload",()=>{L&&L.destroy()});const za=["src","alt"],Ra={key:2,class:"absolute inset-0 flex items-center justify-center"},Ta=["alt"],Ga=F({__name:"LazyImage",props:{src:{},alt:{default:""},containerClass:{type:[Array,Object,String,Number,null,Boolean],default:""},imageClass:{type:[Array,Object,String,Number,null,Boolean],default:""},imageStyle:{},rootMargin:{default:"300px"}},setup(i){const e=x(null),n=x(!1),s=x(!1),t=x(!1),o=x(void 0),{getCachedMedia:a,acquireUrl:l,releaseUrl:c}=Da();Aa(e,v=>{const M=v[0];n.value=M?.isIntersecting??!1},{rootMargin:i.rootMargin,threshold:.1});const y=V(()=>n.value);G(y,async v=>{if(v&&i.src&&!o.value&&!t.value)try{const M=await a(i.src);if(M.error)t.value=!0;else if(M.objectUrl){const A=l(i.src);o.value=A||M.objectUrl}else o.value=i.src}catch(M){console.warn("Failed to load cached media:",M),o.value=i.src}else v||(o.value?.startsWith("blob:")&&c(i.src),s.value=!1,o.value=void 0,t.value=!1)},{immediate:!0});const k=m(()=>{s.value=!0,t.value=!1},"onImageLoad"),h=m(()=>{t.value=!0,s.value=!1},"onImageError");return Ie(()=>{o.value?.startsWith("blob:")&&c(i.src)}),(v,M)=>(d(),g("div",{ref_key:"containerRef",ref:e,class:Z(["relative flex h-full w-full items-center justify-center overflow-hidden",v.containerClass])},[s.value?_("",!0):(d(),C(p(Ve),{key:0,width:"100%",height:"100%",class:"absolute inset-0"})),o.value?(d(),g("img",{key:1,src:o.value,alt:v.alt,draggable:"false",class:Z(v.imageClass),style:ee(v.imageStyle),onLoad:k,onError:h},null,46,za)):_("",!0),t.value?(d(),g("div",Ra,[r("img",{src:ja,alt:v.alt,draggable:"false",class:Z(v.imageClass),style:ee(v.imageStyle)},null,14,Ta)])):_("",!0)],2))}});export{ze as _,Na as a,ja as b,Ga as c,Aa as d,D as u};
2
+ //# sourceMappingURL=LazyImage.vue_vue_type_script_setup_true_lang-BSzd4gKh.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"LazyImage.vue_vue_type_script_setup_true_lang-BSzd4gKh.js","sources":["../../src/composables/useFeatureFlags.ts","../../src/components/input/SingleSelect.vue","../../src/platform/assets/composables/useModelTypes.ts","../../src/platform/assets/components/UploadModelConfirmation.vue","../../src/platform/assets/components/VideoHelpDialog.vue","../../src/platform/assets/components/UploadModelFooter.vue","../../src/platform/assets/importSources/civitaiImportSource.ts","../../src/platform/assets/importSources/huggingfaceImportSource.ts","../../src/platform/assets/utils/importSourceUtil.ts","../../src/platform/assets/components/UploadModelUrlInput.vue","../../src/platform/assets/components/UploadModelUrlInputCivitai.vue","../../src/platform/assets/composables/useUploadModelWizard.ts","../../src/platform/assets/components/UploadModelDialog.vue","../../../../../../../assets/images/civitai.svg","../../src/platform/assets/components/UploadModelDialogHeader.vue","../../src/platform/assets/components/UploadModelUpgradeModalBody.vue","../../src/platform/assets/components/UploadModelUpgradeModalFooter.vue","../../src/platform/assets/components/UploadModelUpgradeModal.vue","../../src/platform/assets/components/UploadModelUpgradeModalHeader.vue","../../src/platform/assets/composables/useModelUpload.ts","../../../../../../../assets/images/default-template.png","../../src/composables/useIntersectionObserver.ts","../../src/services/mediaCacheService.ts","../../src/components/common/LazyImage.vue"],"sourcesContent":["import { computed, reactive, readonly } from 'vue'\n\nimport { remoteConfig } from '@/platform/remoteConfig/remoteConfig'\nimport { api } from '@/scripts/api'\n\n/**\n * Known server feature flags (top-level, not extensions)\n */\nexport enum ServerFeatureFlag {\n SUPPORTS_PREVIEW_METADATA = 'supports_preview_metadata',\n MAX_UPLOAD_SIZE = 'max_upload_size',\n MANAGER_SUPPORTS_V4 = 'extension.manager.supports_v4',\n MODEL_UPLOAD_BUTTON_ENABLED = 'model_upload_button_enabled',\n ASSET_DELETION_ENABLED = 'asset_deletion_enabled',\n ASSET_RENAME_ENABLED = 'asset_rename_enabled',\n PRIVATE_MODELS_ENABLED = 'private_models_enabled',\n ONBOARDING_SURVEY_ENABLED = 'onboarding_survey_enabled',\n HUGGINGFACE_MODEL_IMPORT_ENABLED = 'huggingface_model_import_enabled',\n ASYNC_MODEL_UPLOAD_ENABLED = 'async_model_upload_enabled'\n}\n\n/**\n * Composable for reactive access to server-side feature flags\n */\nexport function useFeatureFlags() {\n const flags = reactive({\n get supportsPreviewMetadata() {\n return api.getServerFeature(ServerFeatureFlag.SUPPORTS_PREVIEW_METADATA)\n },\n get maxUploadSize() {\n return api.getServerFeature(ServerFeatureFlag.MAX_UPLOAD_SIZE)\n },\n get supportsManagerV4() {\n return api.getServerFeature(ServerFeatureFlag.MANAGER_SUPPORTS_V4)\n },\n get modelUploadButtonEnabled() {\n // Check remote config first (from /api/features), fall back to websocket feature flags\n return (\n remoteConfig.value.model_upload_button_enabled ??\n api.getServerFeature(\n ServerFeatureFlag.MODEL_UPLOAD_BUTTON_ENABLED,\n false\n )\n )\n },\n get assetDeletionEnabled() {\n return (\n remoteConfig.value.asset_deletion_enabled ??\n api.getServerFeature(ServerFeatureFlag.ASSET_DELETION_ENABLED, false)\n )\n },\n get assetRenameEnabled() {\n return (\n remoteConfig.value.asset_rename_enabled ??\n api.getServerFeature(ServerFeatureFlag.ASSET_RENAME_ENABLED, false)\n )\n },\n get privateModelsEnabled() {\n // Check remote config first (from /api/features), fall back to websocket feature flags\n return (\n remoteConfig.value.private_models_enabled ??\n api.getServerFeature(ServerFeatureFlag.PRIVATE_MODELS_ENABLED, false)\n )\n },\n get onboardingSurveyEnabled() {\n return (\n remoteConfig.value.onboarding_survey_enabled ??\n api.getServerFeature(ServerFeatureFlag.ONBOARDING_SURVEY_ENABLED, true)\n )\n },\n get huggingfaceModelImportEnabled() {\n return (\n remoteConfig.value.huggingface_model_import_enabled ??\n api.getServerFeature(\n ServerFeatureFlag.HUGGINGFACE_MODEL_IMPORT_ENABLED,\n false\n )\n )\n },\n get asyncModelUploadEnabled() {\n return (\n remoteConfig.value.async_model_upload_enabled ??\n api.getServerFeature(\n ServerFeatureFlag.ASYNC_MODEL_UPLOAD_ENABLED,\n false\n )\n )\n }\n })\n\n const featureFlag = <T = unknown>(featurePath: string, defaultValue?: T) =>\n computed(() => api.getServerFeature(featurePath, defaultValue))\n\n return {\n flags: readonly(flags),\n featureFlag\n }\n}\n","<template>\n <!--\n Note: We explicitly pass options here (not just via $attrs) because:\n 1. Our custom value template needs options to look up labels from values\n 2. PrimeVue's value slot only provides 'value' and 'placeholder', not the selected item's label\n 3. We need to maintain the icon slot functionality in the value template\n option-label=\"name\" is required because our option template directly accesses option.name\n -->\n <Select\n v-model=\"selectedItem\"\n v-bind=\"$attrs\"\n :options=\"options\"\n option-label=\"name\"\n option-value=\"value\"\n unstyled\n :pt=\"{\n root: ({ props }: SelectPassThroughMethodOptions<SelectOption>) => ({\n class: [\n // container\n 'h-10 relative inline-flex cursor-pointer select-none items-center',\n // trigger surface\n 'rounded-lg',\n 'bg-secondary-background text-base-foreground',\n 'border-[2.5px] border-solid border-transparent',\n 'transition-all duration-200 ease-in-out',\n 'focus-within:border-node-component-border',\n // disabled\n { 'opacity-60 cursor-default': props.disabled }\n ]\n }),\n label: {\n class:\n // Align with MultiSelect labelContainer spacing\n 'flex-1 flex items-center whitespace-nowrap pl-4 py-2 outline-hidden'\n },\n dropdown: {\n class:\n // Right chevron touch area\n 'flex shrink-0 items-center justify-center px-3 py-2'\n },\n overlay: {\n class: cn(\n 'mt-2 p-2 rounded-lg',\n 'bg-base-background text-base-foreground',\n 'border border-solid border-border-default'\n )\n },\n listContainer: () => ({\n style: `max-height: min(${listMaxHeight}, 50vh)`,\n class: 'scrollbar-custom'\n }),\n list: {\n class:\n // Same list tone/size as MultiSelect\n 'flex flex-col gap-0 p-0 m-0 list-none border-none text-sm'\n },\n option: ({ context }: SelectPassThroughMethodOptions<SelectOption>) => ({\n class: cn(\n // Row layout\n 'flex items-center justify-between gap-3 px-2 py-3 rounded',\n 'hover:bg-secondary-background-hover',\n // Add focus state for keyboard navigation\n context.focused && 'bg-secondary-background-hover',\n // Selected state + check icon\n context.selected &&\n 'bg-secondary-background-selected hover:bg-secondary-background-selected'\n )\n }),\n optionLabel: {\n class: 'truncate'\n },\n optionGroupLabel: {\n class: 'px-3 py-2 text-xs uppercase tracking-wide text-muted-foreground'\n },\n emptyMessage: {\n class: 'px-3 py-2 text-sm text-muted-foreground'\n }\n }\"\n :aria-label=\"label || t('g.singleSelectDropdown')\"\n role=\"combobox\"\n :aria-expanded=\"false\"\n aria-haspopup=\"listbox\"\n :tabindex=\"0\"\n >\n <!-- Trigger value -->\n <template #value=\"slotProps\">\n <div class=\"flex items-center gap-2 text-sm\">\n <slot name=\"icon\" />\n <span\n v-if=\"slotProps.value !== null && slotProps.value !== undefined\"\n class=\"text-base-foreground\"\n >\n {{ getLabel(slotProps.value) }}\n </span>\n <span v-else class=\"text-base-foreground\">\n {{ label }}\n </span>\n </div>\n </template>\n\n <!-- Trigger caret -->\n <template #dropdownicon>\n <i class=\"icon-[lucide--chevron-down] text-muted-foreground\" />\n </template>\n\n <!-- Option row -->\n <template #option=\"{ option, selected }\">\n <div\n class=\"flex w-full items-center justify-between gap-3\"\n :style=\"optionStyle\"\n >\n <span class=\"truncate\">{{ option.name }}</span>\n <i v-if=\"selected\" class=\"icon-[lucide--check] text-base-foreground\" />\n </div>\n </template>\n </Select>\n</template>\n\n<script setup lang=\"ts\">\nimport type { SelectPassThroughMethodOptions } from 'primevue/select'\nimport Select from 'primevue/select'\nimport { computed } from 'vue'\nimport { useI18n } from 'vue-i18n'\n\nimport { cn } from '@/utils/tailwindUtil'\n\nimport type { SelectOption } from './types'\n\ndefineOptions({\n inheritAttrs: false\n})\n\nconst {\n label,\n options,\n listMaxHeight = '28rem',\n popoverMinWidth,\n popoverMaxWidth\n} = defineProps<{\n label?: string\n /**\n * Required for displaying the selected item's label.\n * Cannot rely on $attrs alone because we need to access options\n * in getLabel() to map values to their display names.\n */\n options?: SelectOption[]\n /** Maximum height of the dropdown panel (default: 28rem) */\n listMaxHeight?: string\n /** Minimum width of the popover (default: auto) */\n popoverMinWidth?: string\n /** Maximum width of the popover (default: auto) */\n popoverMaxWidth?: string\n}>()\n\nconst selectedItem = defineModel<string | undefined>({ required: true })\n\nconst { t } = useI18n()\n\n/**\n * Maps a value to its display label.\n * Necessary because PrimeVue's value slot doesn't provide the selected item's label,\n * only the raw value. We need this to show the correct text when an item is selected.\n */\nconst getLabel = (val: string | null | undefined) => {\n if (val == null) return label ?? ''\n if (!options) return label ?? ''\n const found = options.find((o) => o.value === val)\n return found ? found.name : (label ?? '')\n}\n\n// Extract complex style logic from template\nconst optionStyle = computed(() => {\n if (!popoverMinWidth && !popoverMaxWidth) return undefined\n\n const styles: string[] = []\n if (popoverMinWidth) styles.push(`min-width: ${popoverMinWidth}`)\n if (popoverMaxWidth) styles.push(`max-width: ${popoverMaxWidth}`)\n\n return styles.join('; ')\n})\n</script>\n","import { createSharedComposable, useAsyncState } from '@vueuse/core'\n\nimport { api } from '@/scripts/api'\n\n/**\n * Format folder name to display name\n * Converts \"upscale_models\" -> \"Upscale Model\"\n * Converts \"loras\" -> \"LoRA\"\n */\nfunction formatDisplayName(folderName: string): string {\n // Special cases for acronyms and proper nouns\n const specialCases: Record<string, string> = {\n loras: 'LoRA',\n ipadapter: 'IP-Adapter',\n sams: 'SAM',\n clip_vision: 'CLIP Vision',\n animatediff_motion_lora: 'AnimateDiff Motion LoRA',\n animatediff_models: 'AnimateDiff Model',\n vae: 'VAE',\n sam2: 'SAM 2',\n controlnet: 'ControlNet',\n gligen: 'GLIGEN'\n }\n\n if (specialCases[folderName]) {\n return specialCases[folderName]\n }\n\n return folderName\n .split('_')\n .map((word) => word.charAt(0).toUpperCase() + word.slice(1))\n .join(' ')\n}\n\ninterface ModelTypeOption {\n name: string // Display name\n value: string // Actual tag value\n}\n\nconst DISALLOWED_MODEL_TYPES = ['nlf'] as const\n\n/**\n * Composable for fetching and managing model types from the API\n * Uses shared state to ensure data is only fetched once\n */\nexport const useModelTypes = createSharedComposable(() => {\n const {\n state: modelTypes,\n isLoading,\n error,\n execute: fetchModelTypes\n } = useAsyncState(\n async (): Promise<ModelTypeOption[]> => {\n const response = await api.getModelFolders()\n return response\n .filter(\n (folder) =>\n !DISALLOWED_MODEL_TYPES.includes(\n folder.name as (typeof DISALLOWED_MODEL_TYPES)[number]\n )\n )\n .map((folder) => ({\n name: formatDisplayName(folder.name),\n value: folder.name\n }))\n .sort((a, b) => a.name.localeCompare(b.name))\n },\n [] as ModelTypeOption[],\n {\n immediate: false,\n onError: (err) => {\n console.error('Failed to fetch model types:', err)\n }\n }\n )\n\n return {\n modelTypes,\n isLoading,\n error,\n fetchModelTypes\n }\n})\n","<template>\n <div class=\"flex flex-col gap-4 text-sm text-muted-foreground\">\n <div class=\"flex flex-col gap-2\">\n <p class=\"m-0\">\n {{ $t('assetBrowser.modelAssociatedWithLink') }}\n </p>\n <div\n class=\"flex items-center gap-3 rounded-lg bg-secondary-background px-4 py-2\"\n >\n <img\n v-if=\"previewImage\"\n :src=\"previewImage\"\n :alt=\"metadata?.filename || metadata?.name || 'Model preview'\"\n class=\"size-14 flex-shrink-0 rounded object-cover\"\n />\n <p class=\"m-0 min-w-0 flex-1 truncate text-base-foreground\">\n {{ metadata?.filename || metadata?.name }}\n </p>\n </div>\n </div>\n\n <!-- Model Type Selection -->\n <div class=\"flex flex-col gap-2\">\n <div class=\"flex items-center gap-2\">\n <label>\n {{ $t('assetBrowser.modelTypeSelectorLabel') }}\n </label>\n <i class=\"icon-[lucide--circle-question-mark] text-muted-foreground\" />\n <span class=\"text-muted-foreground\">\n {{ $t('assetBrowser.notSureLeaveAsIs') }}\n </span>\n </div>\n <SingleSelect\n v-model=\"modelValue\"\n :label=\"\n isLoading\n ? $t('g.loading')\n : $t('assetBrowser.modelTypeSelectorPlaceholder')\n \"\n :options=\"modelTypes\"\n :disabled=\"isLoading\"\n data-attr=\"upload-model-step2-type-selector\"\n />\n </div>\n </div>\n</template>\n\n<script setup lang=\"ts\">\nimport SingleSelect from '@/components/input/SingleSelect.vue'\nimport { useModelTypes } from '@/platform/assets/composables/useModelTypes'\nimport type { AssetMetadata } from '@/platform/assets/schemas/assetSchema'\n\ndefineProps<{\n metadata?: AssetMetadata\n previewImage?: string\n}>()\n\nconst modelValue = defineModel<string | undefined>()\n\nconst { modelTypes, isLoading } = useModelTypes()\n</script>\n","<template>\n <Dialog\n v-model:visible=\"isVisible\"\n modal\n :closable=\"false\"\n :close-on-escape=\"false\"\n :dismissable-mask=\"true\"\n :pt=\"{\n root: { class: 'video-help-dialog' },\n header: { class: '!hidden' },\n content: { class: '!p-0' },\n mask: { class: '!bg-black/70' }\n }\"\n :style=\"{ width: '90vw' }\"\n >\n <div class=\"relative\">\n <Button\n variant=\"textonly\"\n size=\"icon\"\n class=\"absolute top-4 right-6 z-10\"\n :aria-label=\"$t('g.close')\"\n @click=\"isVisible = false\"\n >\n <i class=\"pi pi-times text-sm\" />\n </Button>\n <video\n autoplay\n muted\n loop\n :aria-label=\"ariaLabel\"\n class=\"w-full rounded-lg\"\n :src=\"videoUrl\"\n >\n {{ $t('g.videoFailedToLoad') }}\n </video>\n </div>\n </Dialog>\n</template>\n\n<script setup lang=\"ts\">\nimport { useEventListener } from '@vueuse/core'\nimport Dialog from 'primevue/dialog'\nimport { onWatcherCleanup, watch } from 'vue'\n\nimport Button from '@/components/ui/button/Button.vue'\n\nconst isVisible = defineModel<boolean>({ required: true })\n\nconst { videoUrl, ariaLabel = 'Help video' } = defineProps<{\n videoUrl: string\n ariaLabel?: string\n}>()\n\nconst handleEscapeKey = (event: KeyboardEvent) => {\n if (event.key === 'Escape') {\n event.stopImmediatePropagation()\n event.stopPropagation()\n event.preventDefault()\n isVisible.value = false\n }\n}\n\n// Add listener with capture phase to intercept before parent dialogs\n// Only active when dialog is visible\nwatch(\n isVisible,\n (visible) => {\n if (visible) {\n const stop = useEventListener(document, 'keydown', handleEscapeKey, {\n capture: true\n })\n onWatcherCleanup(stop)\n }\n },\n { immediate: true }\n)\n</script>\n","<template>\n <div class=\"flex justify-end gap-2 w-full\">\n <div\n v-if=\"currentStep === 1 && flags.huggingfaceModelImportEnabled\"\n class=\"mr-auto flex items-center gap-2\"\n >\n <i class=\"icon-[lucide--circle-question-mark] text-muted-foreground\" />\n <Button\n variant=\"muted-textonly\"\n size=\"sm\"\n data-attr=\"upload-model-step1-help-civitai\"\n @click=\"showCivitaiHelp = true\"\n >\n {{ $t('assetBrowser.providerCivitai') }}\n </Button>\n <Button\n variant=\"muted-textonly\"\n size=\"sm\"\n data-attr=\"upload-model-step1-help-huggingface\"\n @click=\"showHuggingFaceHelp = true\"\n >\n {{ $t('assetBrowser.providerHuggingFace') }}\n </Button>\n </div>\n <Button\n v-else-if=\"currentStep === 1\"\n variant=\"muted-textonly\"\n size=\"lg\"\n class=\"mr-auto underline\"\n data-attr=\"upload-model-step1-help-link\"\n @click=\"showCivitaiHelp = true\"\n >\n <i class=\"icon-[lucide--circle-question-mark]\" />\n <span>{{ $t('assetBrowser.uploadModelHowDoIFindThis') }}</span>\n </Button>\n <Button\n v-if=\"currentStep === 1\"\n variant=\"muted-textonly\"\n size=\"lg\"\n data-attr=\"upload-model-step1-cancel-button\"\n :disabled=\"isFetchingMetadata || isUploading\"\n @click=\"emit('close')\"\n >\n {{ $t('g.cancel') }}\n </Button>\n <Button\n v-if=\"currentStep !== 1 && currentStep !== 3\"\n variant=\"muted-textonly\"\n size=\"lg\"\n :data-attr=\"`upload-model-step${currentStep}-back-button`\"\n :disabled=\"isFetchingMetadata || isUploading\"\n @click=\"emit('back')\"\n >\n {{ $t('g.back') }}\n </Button>\n <span v-else />\n\n <Button\n v-if=\"currentStep === 1\"\n variant=\"secondary\"\n size=\"lg\"\n data-attr=\"upload-model-step1-continue-button\"\n :disabled=\"!canFetchMetadata || isFetchingMetadata\"\n @click=\"emit('fetchMetadata')\"\n >\n <i\n v-if=\"isFetchingMetadata\"\n class=\"icon-[lucide--loader-circle] animate-spin\"\n />\n <span>{{ $t('g.continue') }}</span>\n </Button>\n <Button\n v-else-if=\"currentStep === 2\"\n variant=\"secondary\"\n size=\"lg\"\n data-attr=\"upload-model-step2-confirm-button\"\n :disabled=\"!canUploadModel || isUploading\"\n @click=\"emit('upload')\"\n >\n <i v-if=\"isUploading\" class=\"icon-[lucide--loader-circle] animate-spin\" />\n <span>{{ $t('assetBrowser.upload') }}</span>\n </Button>\n <template\n v-else-if=\"\n currentStep === 3 &&\n (uploadStatus === 'success' || uploadStatus === 'processing')\n \"\n >\n <Button\n variant=\"muted-textonly\"\n size=\"lg\"\n data-attr=\"upload-model-step3-import-another-button\"\n @click=\"emit('importAnother')\"\n >\n {{ $t('assetBrowser.importAnother') }}\n </Button>\n <Button\n variant=\"secondary\"\n size=\"lg\"\n data-attr=\"upload-model-step3-finish-button\"\n @click=\"emit('close')\"\n >\n {{\n uploadStatus === 'processing'\n ? $t('g.close')\n : $t('assetBrowser.finish')\n }}\n </Button>\n </template>\n <VideoHelpDialog\n v-model=\"showCivitaiHelp\"\n video-url=\"https://media.comfy.org/compressed_768/civitai_howto.webm\"\n :aria-label=\"$t('assetBrowser.uploadModelHelpVideo')\"\n />\n <VideoHelpDialog\n v-model=\"showHuggingFaceHelp\"\n video-url=\"https://media.comfy.org/byom/huggingfacehowto.mp4\"\n :aria-label=\"$t('assetBrowser.uploadModelHelpVideo')\"\n />\n </div>\n</template>\n\n<script setup lang=\"ts\">\nimport { ref } from 'vue'\n\nimport Button from '@/components/ui/button/Button.vue'\nimport { useFeatureFlags } from '@/composables/useFeatureFlags'\nimport VideoHelpDialog from '@/platform/assets/components/VideoHelpDialog.vue'\n\nconst { flags } = useFeatureFlags()\n\nconst showCivitaiHelp = ref(false)\nconst showHuggingFaceHelp = ref(false)\n\ndefineProps<{\n currentStep: number\n isFetchingMetadata: boolean\n isUploading: boolean\n canFetchMetadata: boolean\n canUploadModel: boolean\n uploadStatus?: 'processing' | 'success' | 'error'\n}>()\n\nconst emit = defineEmits<{\n (e: 'back'): void\n (e: 'fetchMetadata'): void\n (e: 'upload'): void\n (e: 'close'): void\n (e: 'importAnother'): void\n}>()\n</script>\n","import type { ImportSource } from '@/platform/assets/types/importSource'\n\n/**\n * Civitai model import source configuration\n */\nexport const civitaiImportSource: ImportSource = {\n type: 'civitai',\n name: 'Civitai',\n hostnames: ['civitai.com']\n}\n","import type { ImportSource } from '@/platform/assets/types/importSource'\n\n/**\n * Hugging Face model import source configuration\n */\nexport const huggingfaceImportSource: ImportSource = {\n type: 'huggingface',\n name: 'Hugging Face',\n hostnames: ['huggingface.co']\n}\n","import type { ImportSource } from '@/platform/assets/types/importSource'\n\n/**\n * Check if a URL belongs to a specific import source\n */\nexport function validateSourceUrl(url: string, source: ImportSource): boolean {\n try {\n const hostname = new URL(url).hostname.toLowerCase()\n return source.hostnames.some(\n (h) => hostname === h || hostname.endsWith(`.${h}`)\n )\n } catch {\n return false\n }\n}\n","<template>\n <div class=\"flex flex-col justify-between h-full gap-6 text-sm\">\n <div class=\"flex flex-col gap-6\">\n <div class=\"flex flex-col gap-2\">\n <p class=\"m-0 text-foreground\">\n {{ $t('assetBrowser.uploadModelDescription1Generic') }}\n </p>\n <div class=\"m-0\">\n <p class=\"m-0 text-muted-foreground\">\n {{ $t('assetBrowser.uploadModelDescription2Generic') }}\n </p>\n <span class=\"inline-flex items-center gap-1 flex-wrap mt-2\">\n <span class=\"inline-flex items-center gap-1\">\n <img\n :src=\"civitaiIcon\"\n :alt=\"$t('assetBrowser.providerCivitai')\"\n class=\"w-4 h-4\"\n />\n <a\n :href=\"civitaiUrl\"\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n class=\"text-muted-foreground underline\"\n >\n {{ $t('assetBrowser.providerCivitai') }}</a\n ><span>,</span>\n </span>\n <span class=\"inline-flex items-center gap-1\">\n <img\n :src=\"huggingFaceIcon\"\n :alt=\"$t('assetBrowser.providerHuggingFace')\"\n class=\"w-4 h-4\"\n />\n <a\n :href=\"huggingFaceUrl\"\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n class=\"text-muted-foreground underline\"\n >\n {{ $t('assetBrowser.providerHuggingFace') }}\n </a>\n </span>\n </span>\n </div>\n </div>\n\n <div class=\"flex flex-col gap-2\">\n <div class=\"relative\">\n <InputText\n v-model=\"url\"\n autofocus\n :placeholder=\"$t('assetBrowser.genericLinkPlaceholder')\"\n class=\"w-full border-0 bg-secondary-background p-4 pr-10\"\n data-attr=\"upload-model-step1-url-input\"\n />\n <i\n v-if=\"isValidUrl\"\n class=\"icon-[lucide--circle-check-big] absolute top-1/2 right-3 size-5 -translate-y-1/2 text-green-500\"\n />\n </div>\n <p v-if=\"error\" class=\"text-sm text-error\">\n {{ error }}\n </p>\n <p v-else-if=\"!flags.asyncModelUploadEnabled\" class=\"text-foreground\">\n <i18n-t keypath=\"assetBrowser.maxFileSize\" tag=\"span\">\n <template #size>\n <span class=\"font-bold italic\">{{\n $t('assetBrowser.maxFileSizeValue')\n }}</span>\n </template>\n </i18n-t>\n </p>\n </div>\n </div>\n\n <div class=\"text-sm text-muted\">\n {{ $t('assetBrowser.uploadModelHelpFooterText') }}\n </div>\n </div>\n</template>\n\n<script setup lang=\"ts\">\nimport InputText from 'primevue/inputtext'\nimport { computed } from 'vue'\n\nimport { useFeatureFlags } from '@/composables/useFeatureFlags'\nimport { civitaiImportSource } from '@/platform/assets/importSources/civitaiImportSource'\nimport { huggingfaceImportSource } from '@/platform/assets/importSources/huggingfaceImportSource'\nimport { validateSourceUrl } from '@/platform/assets/utils/importSourceUtil'\n\nconst { flags } = useFeatureFlags()\n\nconst props = defineProps<{\n modelValue: string\n error?: string\n}>()\n\nconst emit = defineEmits<{\n 'update:modelValue': [value: string]\n}>()\n\nconst url = computed({\n get: () => props.modelValue,\n set: (value: string) => emit('update:modelValue', value)\n})\n\nconst importSources = [civitaiImportSource, huggingfaceImportSource]\n\nconst isValidUrl = computed(() => {\n const trimmedUrl = url.value.trim()\n if (!trimmedUrl) return false\n return importSources.some((source) => validateSourceUrl(trimmedUrl, source))\n})\n\nconst civitaiIcon = '/assets/images/civitai.svg'\nconst civitaiUrl = 'https://civitai.com/models'\nconst huggingFaceIcon = '/assets/images/hf-logo.svg'\nconst huggingFaceUrl = 'https://huggingface.co'\n</script>\n","<template>\n <div class=\"flex flex-col gap-6 text-sm text-muted-foreground\">\n <div class=\"flex flex-col gap-2\">\n <p class=\"m-0\">\n {{ $t('assetBrowser.uploadModelDescription1') }}\n </p>\n <ul class=\"list-disc space-y-1 pl-5 mt-0\">\n <li>\n <i18n-t keypath=\"assetBrowser.uploadModelDescription2\" tag=\"span\">\n <template #link>\n <a\n href=\"https://civitai.com/models\"\n target=\"_blank\"\n class=\"text-muted-foreground underline\"\n >\n {{ $t('assetBrowser.uploadModelDescription2Link') }}\n </a>\n </template>\n </i18n-t>\n </li>\n <li v-if=\"!flags.asyncModelUploadEnabled\">\n <i18n-t keypath=\"assetBrowser.uploadModelDescription3\" tag=\"span\">\n <template #size>\n <span class=\"font-bold italic\">{{\n $t('assetBrowser.maxFileSizeValue')\n }}</span>\n </template>\n </i18n-t>\n </li>\n </ul>\n </div>\n\n <div class=\"flex flex-col gap-2\">\n <i18n-t keypath=\"assetBrowser.civitaiLinkLabel\" tag=\"label\" class=\"mb-0\">\n <template #download>\n <span class=\"font-bold italic\">{{\n $t('assetBrowser.civitaiLinkLabelDownload')\n }}</span>\n </template>\n </i18n-t>\n <div class=\"relative\">\n <InputText\n v-model=\"url\"\n autofocus\n :placeholder=\"$t('assetBrowser.civitaiLinkPlaceholder')\"\n class=\"w-full border-0 bg-secondary-background p-4 pr-10\"\n data-attr=\"upload-model-step1-url-input\"\n />\n <i\n v-if=\"isValidUrl\"\n class=\"icon-[lucide--circle-check-big] absolute top-1/2 right-3 size-5 -translate-y-1/2 text-green-500\"\n />\n </div>\n <p v-if=\"error\" class=\"text-sm text-error\">\n {{ error }}\n </p>\n <i18n-t\n v-else\n keypath=\"assetBrowser.civitaiLinkExample\"\n tag=\"p\"\n class=\"text-sm\"\n >\n <template #example>\n <strong>{{ $t('assetBrowser.civitaiLinkExampleStrong') }}</strong>\n </template>\n <template #link>\n <a\n href=\"https://civitai.com/models/10706/luisap-z-image-and-qwen-pixel-art-refiner?modelVersionId=2225295\"\n target=\"_blank\"\n class=\"text-muted-foreground underline\"\n >\n {{ $t('assetBrowser.civitaiLinkExampleUrl') }}\n </a>\n </template>\n </i18n-t>\n </div>\n </div>\n</template>\n\n<script setup lang=\"ts\">\nimport InputText from 'primevue/inputtext'\nimport { computed } from 'vue'\n\nimport { useFeatureFlags } from '@/composables/useFeatureFlags'\nimport { civitaiImportSource } from '@/platform/assets/importSources/civitaiImportSource'\nimport { validateSourceUrl } from '@/platform/assets/utils/importSourceUtil'\n\nconst { flags } = useFeatureFlags()\n\ndefineProps<{\n error?: string\n}>()\n\nconst url = defineModel<string>({ required: true })\n\nconst isValidUrl = computed(() => {\n const trimmedUrl = url.value.trim()\n if (!trimmedUrl) return false\n return validateSourceUrl(trimmedUrl, civitaiImportSource)\n})\n</script>\n","import type { Ref } from 'vue'\nimport { computed, ref, watch } from 'vue'\nimport { useI18n } from 'vue-i18n'\n\nimport { useFeatureFlags } from '@/composables/useFeatureFlags'\nimport { st } from '@/i18n'\nimport { civitaiImportSource } from '@/platform/assets/importSources/civitaiImportSource'\nimport { huggingfaceImportSource } from '@/platform/assets/importSources/huggingfaceImportSource'\nimport type { AssetMetadata } from '@/platform/assets/schemas/assetSchema'\nimport { assetService } from '@/platform/assets/services/assetService'\nimport type { ImportSource } from '@/platform/assets/types/importSource'\nimport { validateSourceUrl } from '@/platform/assets/utils/importSourceUtil'\nimport { useAssetDownloadStore } from '@/stores/assetDownloadStore'\nimport { useAssetsStore } from '@/stores/assetsStore'\nimport { useModelToNodeStore } from '@/stores/modelToNodeStore'\n\ninterface WizardData {\n url: string\n metadata?: AssetMetadata\n name: string\n tags: string[]\n previewImage?: string\n}\n\ninterface ModelTypeOption {\n name: string\n value: string\n}\n\nexport function useUploadModelWizard(modelTypes: Ref<ModelTypeOption[]>) {\n const { t } = useI18n()\n const assetsStore = useAssetsStore()\n const assetDownloadStore = useAssetDownloadStore()\n const modelToNodeStore = useModelToNodeStore()\n const { flags } = useFeatureFlags()\n const currentStep = ref(1)\n const isFetchingMetadata = ref(false)\n const isUploading = ref(false)\n const uploadStatus = ref<'processing' | 'success' | 'error'>()\n const uploadError = ref('')\n\n const wizardData = ref<WizardData>({\n url: '',\n name: '',\n tags: []\n })\n\n const selectedModelType = ref<string>()\n\n // Available import sources\n const importSources: ImportSource[] = flags.huggingfaceModelImportEnabled\n ? [civitaiImportSource, huggingfaceImportSource]\n : [civitaiImportSource]\n\n // Detected import source based on URL\n const detectedSource = computed(() => {\n const url = wizardData.value.url.trim()\n if (!url) return null\n return (\n importSources.find((source) => validateSourceUrl(url, source)) ?? null\n )\n })\n\n // Clear error when URL changes\n watch(\n () => wizardData.value.url,\n () => {\n uploadError.value = ''\n }\n )\n\n // Validation\n const canFetchMetadata = computed(() => {\n return wizardData.value.url.trim().length > 0\n })\n\n const canUploadModel = computed(() => {\n return !!selectedModelType.value\n })\n\n async function fetchMetadata() {\n if (!canFetchMetadata.value) return\n\n // Clean and normalize URL\n let cleanedUrl = wizardData.value.url.trim()\n try {\n cleanedUrl = new URL(encodeURI(cleanedUrl)).toString()\n } catch {\n // If URL parsing fails, just use the trimmed input\n }\n wizardData.value.url = cleanedUrl\n\n // Validate URL belongs to a supported import source\n const source = detectedSource.value\n if (!source) {\n const supportedSources = importSources.map((s) => s.name).join(', ')\n uploadError.value = t('assetBrowser.unsupportedUrlSource', {\n sources: supportedSources\n })\n return\n }\n\n isFetchingMetadata.value = true\n try {\n const metadata = await assetService.getAssetMetadata(wizardData.value.url)\n\n // Decode URL-encoded filenames (e.g., Chinese characters)\n if (metadata.filename) {\n try {\n metadata.filename = decodeURIComponent(metadata.filename)\n } catch {\n // Keep original if decoding fails\n }\n }\n if (metadata.name) {\n try {\n metadata.name = decodeURIComponent(metadata.name)\n } catch {\n // Keep original if decoding fails\n }\n }\n\n wizardData.value.metadata = metadata\n\n // Pre-fill name from metadata\n wizardData.value.name = metadata.filename || metadata.name || ''\n\n // Store preview image if available\n wizardData.value.previewImage = metadata.preview_image\n\n // Pre-fill model type from metadata tags if available\n if (metadata.tags && metadata.tags.length > 0) {\n wizardData.value.tags = metadata.tags\n // Try to detect model type from tags\n const typeTag = metadata.tags.find((tag) =>\n modelTypes.value.some((type) => type.value === tag)\n )\n if (typeTag) {\n selectedModelType.value = typeTag\n }\n }\n\n currentStep.value = 2\n } catch (error) {\n console.error('Failed to retrieve metadata:', error)\n uploadError.value =\n error instanceof Error\n ? error.message\n : st(\n 'assetBrowser.uploadModelFailedToRetrieveMetadata',\n 'Failed to retrieve metadata. Please check the link and try again.'\n )\n currentStep.value = 1\n } finally {\n isFetchingMetadata.value = false\n }\n }\n\n async function uploadPreviewImage(\n filename: string\n ): Promise<string | undefined> {\n if (!wizardData.value.previewImage) return undefined\n\n try {\n const baseFilename = filename.split('.')[0]\n let extension = 'png'\n const mimeMatch = wizardData.value.previewImage.match(\n /^data:image\\/([^;]+);/\n )\n if (mimeMatch) {\n extension = mimeMatch[1] === 'jpeg' ? 'jpg' : mimeMatch[1]\n }\n\n const previewAsset = await assetService.uploadAssetFromBase64({\n data: wizardData.value.previewImage,\n name: `${baseFilename}_preview.${extension}`,\n tags: ['preview']\n })\n return previewAsset.id\n } catch (error) {\n console.error('Failed to upload preview image:', error)\n return undefined\n }\n }\n\n async function refreshModelCaches() {\n if (!selectedModelType.value) return\n\n const providers = modelToNodeStore.getAllNodeProviders(\n selectedModelType.value\n )\n const results = await Promise.allSettled(\n providers.map((provider) =>\n assetsStore.updateModelsForNodeType(provider.nodeDef.name)\n )\n )\n results.forEach((result, index) => {\n if (result.status === 'rejected') {\n console.error(\n `Failed to refresh ${providers[index].nodeDef.name}:`,\n result.reason\n )\n }\n })\n }\n\n async function uploadModel(): Promise<boolean> {\n if (!canUploadModel.value) {\n return false\n }\n\n const source = detectedSource.value\n if (!source) {\n uploadError.value = t('assetBrowser.noValidSourceDetected')\n return false\n }\n\n isUploading.value = true\n\n try {\n const tags = selectedModelType.value\n ? ['models', selectedModelType.value]\n : ['models']\n const filename =\n wizardData.value.metadata?.filename ||\n wizardData.value.metadata?.name ||\n 'model'\n\n const previewId = await uploadPreviewImage(filename)\n const userMetadata = {\n source: source.type,\n source_url: wizardData.value.url,\n model_type: selectedModelType.value\n }\n\n if (flags.asyncModelUploadEnabled) {\n const result = await assetService.uploadAssetAsync({\n source_url: wizardData.value.url,\n tags,\n user_metadata: userMetadata,\n preview_id: previewId\n })\n\n if (result.type === 'async' && result.task.status !== 'completed') {\n if (selectedModelType.value) {\n assetDownloadStore.trackDownload(\n result.task.task_id,\n selectedModelType.value,\n filename\n )\n }\n uploadStatus.value = 'processing'\n } else {\n uploadStatus.value = 'success'\n await refreshModelCaches()\n }\n currentStep.value = 3\n } else {\n await assetService.uploadAssetFromUrl({\n url: wizardData.value.url,\n name: filename,\n tags,\n user_metadata: userMetadata,\n preview_id: previewId\n })\n uploadStatus.value = 'success'\n await refreshModelCaches()\n currentStep.value = 3\n }\n } catch (error) {\n console.error('Failed to upload asset:', error)\n uploadStatus.value = 'error'\n uploadError.value =\n error instanceof Error ? error.message : 'Failed to upload model'\n currentStep.value = 3\n } finally {\n isUploading.value = false\n }\n return uploadStatus.value !== 'error'\n }\n\n function goToPreviousStep() {\n if (currentStep.value > 1) {\n currentStep.value = currentStep.value - 1\n }\n }\n\n function resetWizard() {\n currentStep.value = 1\n isFetchingMetadata.value = false\n isUploading.value = false\n uploadStatus.value = undefined\n uploadError.value = ''\n wizardData.value = {\n url: '',\n name: '',\n tags: []\n }\n selectedModelType.value = undefined\n }\n\n return {\n // State\n currentStep,\n isFetchingMetadata,\n isUploading,\n uploadStatus,\n uploadError,\n wizardData,\n selectedModelType,\n\n // Computed\n canFetchMetadata,\n canUploadModel,\n detectedSource,\n\n // Actions\n fetchMetadata,\n uploadModel,\n goToPreviousStep,\n resetWizard\n }\n}\n","<template>\n <div\n class=\"upload-model-dialog flex flex-col gap-6 border-t border-border-default p-4 pt-6\"\n >\n <!-- Scrollable content area -->\n <div class=\"min-h-0 flex-auto basis-0 overflow-y-auto\">\n <!-- Step 1: Enter URL -->\n <UploadModelUrlInput\n v-if=\"currentStep === 1 && flags.huggingfaceModelImportEnabled\"\n v-model=\"wizardData.url\"\n :error=\"uploadError\"\n />\n <UploadModelUrlInputCivitai\n v-else-if=\"currentStep === 1\"\n v-model=\"wizardData.url\"\n :error=\"uploadError\"\n />\n\n <!-- Step 2: Confirm Metadata -->\n <UploadModelConfirmation\n v-else-if=\"currentStep === 2\"\n v-model=\"selectedModelType\"\n :metadata=\"wizardData.metadata\"\n :preview-image=\"wizardData.previewImage\"\n />\n\n <!-- Step 3: Upload Progress -->\n <UploadModelProgress\n v-else-if=\"currentStep === 3 && uploadStatus != null\"\n :result=\"uploadStatus\"\n :error=\"uploadError\"\n :metadata=\"wizardData.metadata\"\n :model-type=\"selectedModelType\"\n :preview-image=\"wizardData.previewImage\"\n />\n </div>\n\n <!-- Navigation Footer - always visible -->\n <UploadModelFooter\n class=\"flex-shrink-0\"\n :current-step=\"currentStep\"\n :is-fetching-metadata=\"isFetchingMetadata\"\n :is-uploading=\"isUploading\"\n :can-fetch-metadata=\"canFetchMetadata\"\n :can-upload-model=\"canUploadModel\"\n :upload-status=\"uploadStatus\"\n @back=\"goToPreviousStep\"\n @fetch-metadata=\"handleFetchMetadata\"\n @upload=\"handleUploadModel\"\n @close=\"handleClose\"\n @import-another=\"resetWizard\"\n />\n </div>\n</template>\n\n<script setup lang=\"ts\">\nimport { onMounted } from 'vue'\n\nimport { useFeatureFlags } from '@/composables/useFeatureFlags'\nimport UploadModelConfirmation from '@/platform/assets/components/UploadModelConfirmation.vue'\nimport UploadModelFooter from '@/platform/assets/components/UploadModelFooter.vue'\nimport UploadModelProgress from '@/platform/assets/components/UploadModelProgress.vue'\nimport UploadModelUrlInput from '@/platform/assets/components/UploadModelUrlInput.vue'\nimport UploadModelUrlInputCivitai from '@/platform/assets/components/UploadModelUrlInputCivitai.vue'\nimport { useModelTypes } from '@/platform/assets/composables/useModelTypes'\nimport { useUploadModelWizard } from '@/platform/assets/composables/useUploadModelWizard'\nimport { useDialogStore } from '@/stores/dialogStore'\n\nconst { flags } = useFeatureFlags()\nconst dialogStore = useDialogStore()\nconst { modelTypes, fetchModelTypes } = useModelTypes()\n\nconst emit = defineEmits<{\n 'upload-success': []\n}>()\n\nconst {\n currentStep,\n isFetchingMetadata,\n isUploading,\n uploadStatus,\n uploadError,\n wizardData,\n selectedModelType,\n canFetchMetadata,\n canUploadModel,\n fetchMetadata,\n uploadModel,\n goToPreviousStep,\n resetWizard\n} = useUploadModelWizard(modelTypes)\n\nasync function handleFetchMetadata() {\n await fetchMetadata()\n}\n\nasync function handleUploadModel() {\n const success = await uploadModel()\n if (success) {\n emit('upload-success')\n }\n}\n\nfunction handleClose() {\n dialogStore.closeDialog({ key: 'upload-model' })\n}\n\nonMounted(() => {\n fetchModelTypes()\n})\n</script>\n\n<style scoped>\n.upload-model-dialog {\n width: 90vw;\n max-width: 800px;\n min-height: min(400px, 80vh);\n max-height: 90vh;\n}\n\n@media (min-width: 640px) {\n .upload-model-dialog {\n width: auto;\n min-width: 600px;\n }\n}\n</style>\n","export default \"__VITE_PUBLIC_ASSET__53f47e52__\"","<template>\n <div class=\"flex items-center gap-2 p-4 font-bold\">\n <img\n v-if=\"!flags.huggingfaceModelImportEnabled\"\n src=\"/assets/images/civitai.svg\"\n class=\"size-4\"\n />\n <span>{{ $t(titleKey) }}</span>\n <span\n class=\"rounded-full bg-white px-1.5 py-0 text-xxs font-inter font-semibold uppercase text-black\"\n >\n {{ $t('g.beta') }}\n </span>\n </div>\n</template>\n\n<script setup lang=\"ts\">\nimport { computed } from 'vue'\n\nimport { useFeatureFlags } from '@/composables/useFeatureFlags'\n\nconst { flags } = useFeatureFlags()\n\nconst titleKey = computed(() => {\n return flags.huggingfaceModelImportEnabled\n ? 'assetBrowser.uploadModelGeneric'\n : 'assetBrowser.uploadModelFromCivitai'\n})\n</script>\n","<template>\n <div\n class=\"flex flex-1 flex-col items-center justify-center text-base text-muted-foreground\"\n >\n <p class=\"m-0 max-w-md\">\n {{ $t('assetBrowser.upgradeFeatureDescription') }}\n </p>\n </div>\n</template>\n","<template>\n <div class=\"flex flex-wrap justify-end gap-2 w-full\">\n <a\n href=\"https://blog.comfy.org/p/comfy-cloud-new-features-and-pricing\"\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n class=\"text-muted-foreground mr-auto underline flex items-center gap-2\"\n >\n <i class=\"icon-[lucide--external-link]\" />\n <span>{{ $t('g.learnMore') }}</span>\n </a>\n <Button variant=\"textonly\" @click=\"emit('close')\">{{\n $t('g.close')\n }}</Button>\n <Button variant=\"secondary\" @click=\"emit('subscribe')\">\n {{ $t('subscription.required.subscribe') }}\n </Button>\n </div>\n</template>\n\n<script setup lang=\"ts\">\nimport Button from '@/components/ui/button/Button.vue'\n\nconst emit = defineEmits<{\n close: []\n subscribe: []\n}>()\n</script>\n","<template>\n <div\n class=\"flex flex-col justify-between gap-10 p-4 border-t border-border-default w-auto max-w-[min(500px,90vw)]\"\n >\n <UploadModelUpgradeModalBody />\n\n <UploadModelUpgradeModalFooter\n @close=\"handleClose\"\n @subscribe=\"handleSubscribe\"\n />\n </div>\n</template>\n\n<script setup lang=\"ts\">\nimport UploadModelUpgradeModalBody from '@/platform/assets/components/UploadModelUpgradeModalBody.vue'\nimport UploadModelUpgradeModalFooter from '@/platform/assets/components/UploadModelUpgradeModalFooter.vue'\nimport { useSubscription } from '@/platform/cloud/subscription/composables/useSubscription'\nimport { useDialogStore } from '@/stores/dialogStore'\n\nconst dialogStore = useDialogStore()\nconst { showSubscriptionDialog } = useSubscription()\n\nfunction handleClose() {\n dialogStore.closeDialog({ key: 'upload-model-upgrade' })\n}\n\nfunction handleSubscribe() {\n showSubscriptionDialog()\n}\n</script>\n","<template>\n <div class=\"flex items-center gap-2 p-4 font-bold\">\n <span>{{ $t('assetBrowser.upgradeToUnlockFeature') }}</span>\n </div>\n</template>\n","import { useFeatureFlags } from '@/composables/useFeatureFlags'\nimport UploadModelDialog from '@/platform/assets/components/UploadModelDialog.vue'\nimport UploadModelDialogHeader from '@/platform/assets/components/UploadModelDialogHeader.vue'\nimport UploadModelUpgradeModal from '@/platform/assets/components/UploadModelUpgradeModal.vue'\nimport UploadModelUpgradeModalHeader from '@/platform/assets/components/UploadModelUpgradeModalHeader.vue'\nimport { useDialogStore } from '@/stores/dialogStore'\nimport { computed } from 'vue'\n\nexport function useModelUpload(\n onUploadSuccess?: () => Promise<unknown> | void\n) {\n const dialogStore = useDialogStore()\n const { flags } = useFeatureFlags()\n const isUploadButtonEnabled = computed(() => flags.modelUploadButtonEnabled)\n\n function showUploadDialog() {\n if (!flags.privateModelsEnabled) {\n // Show upgrade modal if private models are disabled\n dialogStore.showDialog({\n key: 'upload-model-upgrade',\n headerComponent: UploadModelUpgradeModalHeader,\n component: UploadModelUpgradeModal,\n dialogComponentProps: {\n pt: {\n header: 'py-0! pl-0!',\n content: 'p-0! overflow-y-hidden!'\n }\n }\n })\n } else {\n // Show regular upload modal\n dialogStore.showDialog({\n key: 'upload-model',\n headerComponent: UploadModelDialogHeader,\n component: UploadModelDialog,\n props: {\n onUploadSuccess: async () => {\n await onUploadSuccess?.()\n }\n },\n dialogComponentProps: {\n pt: {\n header: 'py-0! pl-0!',\n content: 'p-0! overflow-y-hidden!'\n }\n }\n })\n }\n }\n return { isUploadButtonEnabled, showUploadDialog }\n}\n","export default \"__VITE_PUBLIC_ASSET__c8cdd13f__\"","import { onBeforeUnmount, ref, watch } from 'vue'\nimport type { Ref } from 'vue'\n\ninterface UseIntersectionObserverOptions extends IntersectionObserverInit {\n immediate?: boolean\n}\n\nexport function useIntersectionObserver(\n target: Ref<Element | null>,\n callback: IntersectionObserverCallback,\n options: UseIntersectionObserverOptions = {}\n) {\n const { immediate = true, ...observerOptions } = options\n\n const isSupported =\n typeof window !== 'undefined' && 'IntersectionObserver' in window\n const isIntersecting = ref(false)\n\n let observer: IntersectionObserver | null = null\n\n const cleanup = () => {\n if (observer) {\n observer.disconnect()\n observer = null\n }\n }\n\n const observe = () => {\n cleanup()\n\n if (!isSupported || !target.value) return\n\n observer = new IntersectionObserver((entries) => {\n isIntersecting.value = entries.some((entry) => entry.isIntersecting)\n callback(entries, observer!)\n }, observerOptions)\n\n observer.observe(target.value)\n }\n\n const unobserve = () => {\n if (observer && target.value) {\n observer.unobserve(target.value)\n }\n }\n\n if (immediate) {\n watch(target, observe, { immediate: true, flush: 'post' })\n }\n\n onBeforeUnmount(cleanup)\n\n return {\n isSupported,\n isIntersecting,\n observe,\n unobserve,\n cleanup\n }\n}\n","import { reactive } from 'vue'\n\ninterface CachedMedia {\n src: string\n blob?: Blob\n objectUrl?: string\n error?: boolean\n isLoading: boolean\n lastAccessed: number\n}\n\ninterface MediaCacheOptions {\n maxSize?: number\n maxAge?: number // in milliseconds\n preloadDistance?: number // pixels from viewport\n}\n\nclass MediaCacheService {\n public cache = reactive(new Map<string, CachedMedia>())\n private readonly maxSize: number\n private readonly maxAge: number\n private cleanupInterval: number | null = null\n private urlRefCount = new Map<string, number>()\n\n constructor(options: MediaCacheOptions = {}) {\n this.maxSize = options.maxSize ?? 100\n this.maxAge = options.maxAge ?? 30 * 60 * 1000 // 30 minutes\n\n // Start cleanup interval\n this.startCleanupInterval()\n }\n\n private startCleanupInterval() {\n // Clean up every 5 minutes\n this.cleanupInterval = window.setInterval(\n () => {\n this.cleanup()\n },\n 5 * 60 * 1000\n )\n }\n\n private cleanup() {\n const now = Date.now()\n const keysToDelete: string[] = []\n\n // Find expired entries\n for (const [key, entry] of Array.from(this.cache.entries())) {\n if (now - entry.lastAccessed > this.maxAge) {\n // Only revoke object URL if no components are using it\n if (entry.objectUrl) {\n const refCount = this.urlRefCount.get(entry.objectUrl) || 0\n if (refCount === 0) {\n URL.revokeObjectURL(entry.objectUrl)\n this.urlRefCount.delete(entry.objectUrl)\n keysToDelete.push(key)\n }\n // Don't delete cache entry if URL is still in use\n } else {\n keysToDelete.push(key)\n }\n }\n }\n\n // Remove expired entries\n keysToDelete.forEach((key) => this.cache.delete(key))\n\n // If still over size limit, remove oldest entries that aren't in use\n if (this.cache.size > this.maxSize) {\n const entries = Array.from(this.cache.entries())\n entries.sort((a, b) => a[1].lastAccessed - b[1].lastAccessed)\n\n let removedCount = 0\n const targetRemoveCount = this.cache.size - this.maxSize\n\n for (const [key, entry] of entries) {\n if (removedCount >= targetRemoveCount) break\n\n if (entry.objectUrl) {\n const refCount = this.urlRefCount.get(entry.objectUrl) || 0\n if (refCount === 0) {\n URL.revokeObjectURL(entry.objectUrl)\n this.urlRefCount.delete(entry.objectUrl)\n this.cache.delete(key)\n removedCount++\n }\n } else {\n this.cache.delete(key)\n removedCount++\n }\n }\n }\n }\n\n async getCachedMedia(src: string): Promise<CachedMedia> {\n let entry = this.cache.get(src)\n\n if (entry) {\n // Update last accessed time\n entry.lastAccessed = Date.now()\n return entry\n }\n\n // Create new entry\n entry = {\n src,\n isLoading: true,\n lastAccessed: Date.now()\n }\n\n // Update cache with loading entry\n this.cache.set(src, entry)\n\n try {\n // Fetch the media\n const response = await fetch(src, { cache: 'force-cache' })\n if (!response.ok) {\n throw new Error(`Failed to fetch: ${response.status}`)\n }\n\n const blob = await response.blob()\n const objectUrl = URL.createObjectURL(blob)\n\n // Update entry with successful result\n const updatedEntry: CachedMedia = {\n src,\n blob,\n objectUrl,\n isLoading: false,\n lastAccessed: Date.now()\n }\n\n this.cache.set(src, updatedEntry)\n return updatedEntry\n } catch (error) {\n console.warn('Failed to cache media:', src, error)\n\n // Update entry with error\n const errorEntry: CachedMedia = {\n src,\n error: true,\n isLoading: false,\n lastAccessed: Date.now()\n }\n\n this.cache.set(src, errorEntry)\n return errorEntry\n }\n }\n\n acquireUrl(src: string): string | undefined {\n const entry = this.cache.get(src)\n if (entry?.objectUrl) {\n const currentCount = this.urlRefCount.get(entry.objectUrl) || 0\n this.urlRefCount.set(entry.objectUrl, currentCount + 1)\n return entry.objectUrl\n }\n return undefined\n }\n\n releaseUrl(src: string): void {\n const entry = this.cache.get(src)\n if (entry?.objectUrl) {\n const count = (this.urlRefCount.get(entry.objectUrl) || 1) - 1\n if (count <= 0) {\n URL.revokeObjectURL(entry.objectUrl)\n this.urlRefCount.delete(entry.objectUrl)\n // Remove from cache as well\n this.cache.delete(src)\n } else {\n this.urlRefCount.set(entry.objectUrl, count)\n }\n }\n }\n\n clearCache() {\n // Revoke all object URLs\n for (const entry of Array.from(this.cache.values())) {\n if (entry.objectUrl) {\n URL.revokeObjectURL(entry.objectUrl)\n }\n }\n this.cache.clear()\n this.urlRefCount.clear()\n }\n\n destroy() {\n if (this.cleanupInterval) {\n clearInterval(this.cleanupInterval)\n this.cleanupInterval = null\n }\n this.clearCache()\n }\n}\n\n// Global instance\nlet mediaCacheInstance: MediaCacheService | null = null\n\nexport function useMediaCache(options?: MediaCacheOptions) {\n if (!mediaCacheInstance) {\n mediaCacheInstance = new MediaCacheService(options)\n }\n\n const getCachedMedia = (src: string) =>\n mediaCacheInstance!.getCachedMedia(src)\n const clearCache = () => mediaCacheInstance!.clearCache()\n const acquireUrl = (src: string) => mediaCacheInstance!.acquireUrl(src)\n const releaseUrl = (src: string) => mediaCacheInstance!.releaseUrl(src)\n\n return {\n getCachedMedia,\n clearCache,\n acquireUrl,\n releaseUrl,\n cache: mediaCacheInstance.cache\n }\n}\n\n// Cleanup on page unload\nif (typeof window !== 'undefined') {\n window.addEventListener('beforeunload', () => {\n if (mediaCacheInstance) {\n mediaCacheInstance.destroy()\n }\n })\n}\n","<template>\n <div\n ref=\"containerRef\"\n class=\"relative flex h-full w-full items-center justify-center overflow-hidden\"\n :class=\"containerClass\"\n >\n <Skeleton\n v-if=\"!isImageLoaded\"\n width=\"100%\"\n height=\"100%\"\n class=\"absolute inset-0\"\n />\n <img\n v-if=\"cachedSrc\"\n :src=\"cachedSrc\"\n :alt=\"alt\"\n draggable=\"false\"\n :class=\"imageClass\"\n :style=\"imageStyle\"\n @load=\"onImageLoad\"\n @error=\"onImageError\"\n />\n <div\n v-if=\"hasError\"\n class=\"absolute inset-0 flex items-center justify-center\"\n >\n <img\n src=\"/assets/images/default-template.png\"\n :alt=\"alt\"\n draggable=\"false\"\n :class=\"imageClass\"\n :style=\"imageStyle\"\n />\n </div>\n </div>\n</template>\n\n<script setup lang=\"ts\">\nimport Skeleton from 'primevue/skeleton'\nimport { computed, onUnmounted, ref, watch } from 'vue'\n\nimport { useIntersectionObserver } from '@/composables/useIntersectionObserver'\nimport { useMediaCache } from '@/services/mediaCacheService'\nimport type { ClassValue } from '@/utils/tailwindUtil'\n\nconst {\n src,\n alt = '',\n containerClass = '',\n imageClass = '',\n imageStyle,\n rootMargin = '300px'\n} = defineProps<{\n src: string\n alt?: string\n containerClass?: ClassValue\n imageClass?: ClassValue\n imageStyle?: Record<string, any>\n rootMargin?: string\n}>()\n\nconst containerRef = ref<HTMLElement | null>(null)\nconst isIntersecting = ref(false)\nconst isImageLoaded = ref(false)\nconst hasError = ref(false)\nconst cachedSrc = ref<string | undefined>(undefined)\n\nconst { getCachedMedia, acquireUrl, releaseUrl } = useMediaCache()\n\n// Use intersection observer to detect when the image container comes into view\nuseIntersectionObserver(\n containerRef,\n (entries) => {\n const entry = entries[0]\n isIntersecting.value = entry?.isIntersecting ?? false\n },\n {\n rootMargin,\n threshold: 0.1\n }\n)\n\n// Only start loading the image when it's in view\nconst shouldLoad = computed(() => isIntersecting.value)\n\nwatch(\n shouldLoad,\n async (shouldLoadVal) => {\n if (shouldLoadVal && src && !cachedSrc.value && !hasError.value) {\n try {\n const cachedMedia = await getCachedMedia(src)\n if (cachedMedia.error) {\n hasError.value = true\n } else if (cachedMedia.objectUrl) {\n const acquiredUrl = acquireUrl(src)\n cachedSrc.value = acquiredUrl || cachedMedia.objectUrl\n } else {\n cachedSrc.value = src\n }\n } catch (error) {\n console.warn('Failed to load cached media:', error)\n cachedSrc.value = src\n }\n } else if (!shouldLoadVal) {\n if (cachedSrc.value?.startsWith('blob:')) {\n releaseUrl(src)\n }\n // Hide image when out of view\n isImageLoaded.value = false\n cachedSrc.value = undefined\n hasError.value = false\n }\n },\n { immediate: true }\n)\n\nconst onImageLoad = () => {\n isImageLoaded.value = true\n hasError.value = false\n}\n\nconst onImageError = () => {\n hasError.value = true\n isImageLoaded.value = false\n}\n\nonUnmounted(() => {\n if (cachedSrc.value?.startsWith('blob:')) {\n releaseUrl(src)\n }\n})\n</script>\n"],"names":["useFeatureFlags","flags","reactive","api","remoteConfig","featureFlag","__name","featurePath","defaultValue","computed","readonly","selectedItem","_useModel","__props","t","useI18n","getLabel","val","found","o","optionStyle","styles","formatDisplayName","folderName","specialCases","word","DISALLOWED_MODEL_TYPES","useModelTypes","createSharedComposable","modelTypes","isLoading","error","fetchModelTypes","useAsyncState","folder","a","b","err","modelValue","isVisible","handleEscapeKey","event","watch","visible","stop","useEventListener","onWatcherCleanup","showCivitaiHelp","ref","showHuggingFaceHelp","emit","__emit","civitaiImportSource","huggingfaceImportSource","validateSourceUrl","url","source","hostname","h","civitaiIcon","civitaiUrl","huggingFaceIcon","huggingFaceUrl","props","value","importSources","isValidUrl","trimmedUrl","useUploadModelWizard","assetsStore","useAssetsStore","assetDownloadStore","useAssetDownloadStore","modelToNodeStore","useModelToNodeStore","currentStep","isFetchingMetadata","isUploading","uploadStatus","uploadError","wizardData","selectedModelType","detectedSource","canFetchMetadata","canUploadModel","fetchMetadata","cleanedUrl","supportedSources","s","metadata","assetService","typeTag","tag","type","st","uploadPreviewImage","filename","baseFilename","extension","mimeMatch","refreshModelCaches","providers","provider","result","index","uploadModel","tags","previewId","userMetadata","goToPreviousStep","resetWizard","dialogStore","useDialogStore","handleFetchMetadata","handleUploadModel","handleClose","onMounted","_imports_0$1","titleKey","_hoisted_1","_hoisted_2","_openBlock","_createElementBlock","_createElementVNode","_toDisplayString","_ctx","showSubscriptionDialog","useSubscription","handleSubscribe","useModelUpload","onUploadSuccess","isUploadButtonEnabled","showUploadDialog","UploadModelDialogHeader","UploadModelDialog","UploadModelUpgradeModalHeader","UploadModelUpgradeModal","_imports_0","useIntersectionObserver","target","callback","options","immediate","observerOptions","isSupported","isIntersecting","observer","cleanup","observe","entries","entry","unobserve","onBeforeUnmount","MediaCacheService","now","keysToDelete","key","removedCount","targetRemoveCount","src","response","blob","objectUrl","updatedEntry","errorEntry","currentCount","count","mediaCacheInstance","useMediaCache","containerRef","isImageLoaded","hasError","cachedSrc","getCachedMedia","acquireUrl","releaseUrl","shouldLoad","shouldLoadVal","cachedMedia","acquiredUrl","onImageLoad","onImageError","onUnmounted"],"mappings":"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"}
@@ -1,2 +1,2 @@
1
- var Q=Object.defineProperty;var l=(h,m)=>Q(h,"name",{value:m,configurable:!0});import{a as O,w as W,g as X,s as Y,ad as z,d as Z,ae as L,q as N,G as ee}from"./vendor-primevue-Bp7MMXLP.js";import{u as V}from"./vendor-vue-DaLZjKA7.js";import{a5 as R,a6 as q,a7 as te,a8 as H,_ as S,o as se,a2 as ae,p as oe,a4 as ne,A as ie,m as re,dv as le}from"./index-DvCHS_f2.js";import{bx as j,E as k,c as $,d as p,e as n,z as c,by as a,j as T,q as I,k as u,u as i,s as G,r as A,w as J,cp as K,h as ce,A as D,l as de}from"./vendor-other-B8t_Wf2K.js";import"./vendor-xterm-CWYFmgbN.js";import"./vendor-three-DH0o8VQ7.js";import"./vendor-tiptap-VxK0yxkd.js";const ue={key:0,class:"flex items-center gap-1"},me={class:"flex items-center gap-2"},pe={key:1,class:"flex items-center gap-1"},fe=j({__name:"UserCredit",props:{textClass:{},showCreditsOnly:{type:Boolean}},setup(h){const m=R(),x=k(()=>m.isFetchingBalance),{t:w,locale:f}=V(),v=k(()=>{const _=m.balance?.effective_balance_micros??m.balance?.amount_micros??0;return`${q({cents:_,locale:f.value})} ${w("credits.credits")}`}),d=k(()=>{const _=m.balance?.effective_balance_micros??m.balance?.amount_micros??0;return q({cents:_,locale:f.value,numberOptions:{minimumFractionDigits:0,maximumFractionDigits:0}})});return(_,g)=>x.value?(p(),$("div",ue,[n("div",me,[c(a(O),{shape:"circle",width:"1.5rem",height:"1.5rem"})]),g[0]||(g[0]=n("div",{class:"flex-1"},null,-1)),c(a(O),{width:"8rem",height:"2rem"})])):(p(),$("div",pe,[_.showCreditsOnly?I("",!0):(p(),T(a(W),{key:0,severity:"secondary",rounded:"",class:"p-1 text-amber-400"},{icon:u(()=>g[1]||(g[1]=[n("i",{class:"icon-[lucide--component]"},null,-1)])),_:1})),n("div",{class:G(_.textClass)},i(_.showCreditsOnly?d.value:v.value),3)]))}});var F=(h=>(h.CREDIT_ADDED="credit_added",h.ACCOUNT_CREATED="account_created",h.API_USAGE_STARTED="api_usage_started",h.API_USAGE_COMPLETED="api_usage_completed",h))(F||{});const M=K.create({baseURL:H(),headers:{"Content-Type":"application/json"}}),ve=l(()=>{const h=A(!1),m=A(null),{d:x}=V();J(()=>H(),e=>{M.defaults.baseURL=e});const w=l((e,s,b)=>{if(te(e))return;let y;if(!K.isAxiosError(e))y=`${s} failed: ${e instanceof Error?e.message:String(e)}`;else{const o=e,r=o.response?.status;r&&b?.[r]?y=b[r]:y=o.response?.data?.message??`${s} failed with status ${r}`}m.value=y},"handleRequestError"),f=l(async(e,s)=>{const{errorContext:b,routeSpecificErrors:y}=s;h.value=!0,m.value=null;try{return(await e()).data}catch(o){return w(o,b,y),null}finally{h.value=!1}},"executeRequest");function v(e){switch(e){case"credit_added":return"Credits Added";case"account_created":return"Account Created";case"api_usage_completed":return"API Usage";default:return e}}l(v,"formatEventType");function d(e){const s=new Date(e);return x(s,{month:"short",day:"numeric",hour:"2-digit",minute:"2-digit"})}l(d,"formatDate");function _(e){return e.split("_").map(s=>s.charAt(0).toUpperCase()+s.slice(1)).join(" ")}l(_,"formatJsonKey");function g(e){return typeof e=="number"?e.toLocaleString():typeof e=="string"&&e.match(/^\d{4}-\d{2}-\d{2}/)?new Date(e).toLocaleString():e}l(g,"formatJsonValue");function P(e){switch(e){case"credit_added":return"success";case"account_created":return"info";case"api_usage_completed":return"warning";default:return"info"}}l(P,"getEventSeverity");function E(e){const{amount:s,api_name:b,model:y,...o}=e.params||{};return Object.keys(o).length>0}l(E,"hasAdditionalInfo");function B(e){const{...s}=e.params||{};return Object.entries(s).map(([b,y])=>{const o=_(b),r=g(y);return`<strong>${o}:</strong> ${r}`}).join("<br>")}l(B,"getTooltipContent");function t(e){return e?(e/100).toFixed(2):"0.00"}l(t,"formatAmount");async function C({page:e=1,limit:s=10}={}){const b="Fetching customer events",y={400:"Invalid input, object invalid",404:"Not found"},o=await R().getAuthHeader();return o?await f(()=>M.get("/customers/events",{params:{page:e,limit:s},headers:o}),{errorContext:b,routeSpecificErrors:y}):(m.value="Authentication header is missing",null)}return l(C,"getMyEvents"),{isLoading:h,error:m,getMyEvents:C,formatEventType:v,getEventSeverity:P,formatAmount:t,hasAdditionalInfo:E,formatDate:d,formatJsonKey:_,formatJsonValue:g,getTooltipContent:B}},"useCustomerEventsService"),ge={key:0,class:"flex items-center justify-center p-8"},he={key:1,class:"p-4"},_e={class:"event-details"},ye={key:0,class:"font-semibold text-green-500"},Ce={key:1},be={key:2,class:"flex flex-col gap-1"},$e={class:"font-semibold"},xe={class:"text-sm text-smoke-400"},we=j({__name:"UsageLogsTable",setup(h,{expose:m}){const x=A([]),w=A(!0),f=A(null),v=ve(),d=A({page:1,limit:7,total:0,totalPages:0}),_=k(()=>(d.value.page-1)*d.value.limit),g=k(()=>{const t=new Map;return x.value.forEach(C=>{v.hasAdditionalInfo(C)&&C.event_id&&t.set(C.event_id,v.getTooltipContent(C))}),t}),P=l(async()=>{w.value=!0,f.value=null;try{const t=await v.getMyEvents({page:d.value.page,limit:d.value.limit});t?(t.events&&(x.value=t.events),t.page&&(d.value.page=t.page),t.limit&&(d.value.limit=t.limit),t.total&&(d.value.total=t.total),t.totalPages&&(d.value.totalPages=t.totalPages),se()?.checkForCompletedTopup(t.events)):f.value=v.error.value||"Failed to load events"}catch(t){f.value=t instanceof Error?t.message:"Unknown error",console.error("Error loading events:",t)}finally{w.value=!1}},"loadEvents"),E=l(t=>{d.value.page=t.page+1,P().catch(C=>{console.error("Error loading events:",C)})},"onPageChange");return m({refresh:l(async()=>{d.value.page=1,await P()},"refresh")}),(t,C)=>{const e=ce("tooltip");return p(),$("div",null,[w.value?(p(),$("div",ge,[c(a(X))])):f.value?(p(),$("div",he,[c(a(Y),{severity:"error",closable:!1},{default:u(()=>[D(i(f.value),1)]),_:1})])):(p(),T(a(z),{key:2,value:x.value,paginator:!0,rows:d.value.limit,"total-records":d.value.total,first:_.value,lazy:!0,class:"p-datatable-sm custom-datatable",onPage:E},{default:u(()=>[c(a(L),{field:"event_type",header:t.$t("credits.eventType")},{body:u(({data:s})=>[c(a(Z),{value:a(v).formatEventType(s.event_type),severity:a(v).getEventSeverity(s.event_type)},null,8,["value","severity"])]),_:1},8,["header"]),c(a(L),{field:"details",header:t.$t("credits.details")},{body:u(({data:s})=>[n("div",_e,[s.event_type===a(F).CREDIT_ADDED?(p(),$("div",ye,i(t.$t("credits.added"))+" $"+i(a(v).formatAmount(s.params?.amount)),1)):s.event_type===a(F).ACCOUNT_CREATED?(p(),$("div",Ce,i(t.$t("credits.accountInitialized")),1)):s.event_type===a(F).API_USAGE_COMPLETED?(p(),$("div",be,[n("div",$e,i(s.params?.api_name||"API"),1),n("div",xe,i(t.$t("credits.model"))+": "+i(s.params?.model||"-"),1)])):I("",!0)])]),_:1},8,["header"]),c(a(L),{field:"createdAt",header:t.$t("credits.time")},{body:u(({data:s})=>[D(i(a(v).formatDate(s.createdAt)),1)]),_:1},8,["header"]),c(a(L),{field:"params",header:t.$t("credits.additionalInfo")},{body:u(({data:s})=>[a(v).hasAdditionalInfo(s)?de((p(),T(S,{key:0,variant:"textonly",size:"icon-sm","aria-label":t.$t("credits.additionalInfo")},{default:u(()=>C[0]||(C[0]=[n("i",{class:"pi pi-info-circle"},null,-1)])),_:2},1032,["aria-label"])),[[e,{escape:!1,value:g.value.get(s.event_id)||"",pt:{text:{style:{width:"max-content !important"}}}},void 0,{top:!0}]]):I("",!0)]),_:1},8,["header"])]),_:1},8,["value","rows","total-records","first"]))])}}}),Ae={class:"flex h-full flex-col"},ke={class:"mb-2 text-2xl font-bold"},Ee={class:"flex flex-col gap-2"},Se={class:"text-sm font-medium text-muted"},De={class:"flex items-center justify-between"},Te={class:"flex flex-row items-center"},Pe={key:1,class:"text-xs text-muted"},Ue={class:"flex items-center justify-between"},Le={key:0,class:"grow"},Ie={class:"text-sm font-medium"},Be={class:"text-xs text-muted"},Fe={class:"flex flex-row gap-2"},He=j({__name:"LegacyCreditsPanel",setup(h){const{buildDocsUrl:m,docsPaths:x}=ae(),w=oe(),f=R(),v=ne(),d=ie(),{isActiveSubscription:_}=re(),g=k(()=>f.loading),P=k(()=>f.isFetchingBalance),E=A(null),B=k(()=>f.lastBalanceUpdateTime?f.lastBalanceUpdateTime.toLocaleString():"");J(()=>f.lastBalanceUpdateTime,(o,r)=>{o&&o!==r&&E.value&&E.value.refresh()});const t=l(()=>{w.showTopUpCreditsDialog()},"handlePurchaseCreditsClick"),C=l(async()=>{await v.accessBillingPortal()},"handleCreditsHistoryClick"),e=l(async()=>{await d.execute("Comfy.ContactSupport")},"handleMessageSupport"),s=l(()=>{window.open(m("/tutorials/api-nodes/faq",{includeLocale:!0}),"_blank")},"handleFaqClick"),b=l(()=>{window.open(m(x.partnerNodesPricing,{includeLocale:!0}),"_blank")},"handleOpenPartnerNodesInfo"),y=A([]);return(o,r)=>(p(),T(a(ee),{value:"Credits",class:"credits-container h-full"},{default:u(()=>[n("div",Ae,[n("h2",ke,i(o.$t("credits.credits")),1),c(a(N)),n("div",Ee,[n("h3",Se,i(o.$t("credits.yourCreditBalance")),1),n("div",De,[c(fe,{"text-class":"text-3xl font-bold"}),g.value?(p(),T(a(O),{key:0,width:"2rem",height:"2rem"})):a(_)?(p(),T(S,{key:1,loading:g.value,onClick:t},{default:u(()=>[D(i(o.$t("credits.purchaseCredits")),1)]),_:1},8,["loading"])):I("",!0)]),n("div",Te,[P.value?(p(),T(a(O),{key:0,width:"12rem",height:"1rem",class:"text-xs"})):B.value?(p(),$("div",Pe,i(o.$t("credits.lastUpdated"))+": "+i(B.value),1)):I("",!0),c(S,{variant:"muted-textonly",size:"icon-sm","aria-label":o.$t("g.refresh"),onClick:r[0]||(r[0]=()=>a(v).fetchBalance())},{default:u(()=>r[1]||(r[1]=[n("i",{class:"pi pi-refresh"},null,-1)])),_:1},8,["aria-label"])])]),n("div",Ue,[n("h3",null,i(o.$t("credits.activity")),1),c(S,{variant:"muted-textonly",loading:g.value,onClick:C},{default:u(()=>[r[2]||(r[2]=n("i",{class:"pi pi-arrow-up-right"},null,-1)),D(" "+i(o.$t("credits.invoiceHistory")),1)]),_:1},8,["loading"])]),y.value.length>0?(p(),$("div",Le,[c(a(z),{value:y.value,"show-headers":!1},{default:u(()=>[c(a(L),{field:"title",header:o.$t("g.name")},{body:u(({data:U})=>[n("div",Ie,i(U.title),1),n("div",Be,i(U.timestamp),1)]),_:1},8,["header"]),c(a(L),{field:"amount",header:o.$t("g.amount")},{body:u(({data:U})=>[n("div",{class:G(["text-center text-base font-medium",U.isPositive?"text-sky-500":"text-red-400"])},i(U.isPositive?"+":"-")+"$"+i(a(le)(U.amount,"usd")),3)]),_:1},8,["header"])]),_:1},8,["value"])])):I("",!0),c(a(N)),c(we,{ref_key:"usageLogsTableRef",ref:E},null,512),n("div",Fe,[c(S,{variant:"muted-textonly",onClick:s},{default:u(()=>[r[3]||(r[3]=n("i",{class:"pi pi-question-circle"},null,-1)),D(" "+i(o.$t("credits.faqs")),1)]),_:1}),c(S,{variant:"muted-textonly",onClick:b},{default:u(()=>[r[4]||(r[4]=n("i",{class:"pi pi-question-circle"},null,-1)),D(" "+i(o.$t("subscription.partnerNodesCredits")),1)]),_:1}),c(S,{variant:"muted-textonly",onClick:e},{default:u(()=>[r[5]||(r[5]=n("i",{class:"pi pi-comments"},null,-1)),D(" "+i(o.$t("credits.messageSupport")),1)]),_:1})])])]),_:1}))}});export{He as default};
2
- //# sourceMappingURL=LegacyCreditsPanel-Be7L1Af3.js.map
1
+ var Q=Object.defineProperty;var l=(h,m)=>Q(h,"name",{value:m,configurable:!0});import{a as O,w as W,g as X,s as Y,ad as z,d as Z,ae as L,q as N,G as ee}from"./vendor-primevue-DeKsC2uk.js";import{u as V}from"./vendor-vue-DaLZjKA7.js";import{a6 as R,a7 as q,a8 as te,a9 as H,_ as S,o as se,a3 as ae,p as oe,a5 as ne,A as ie,m as re,dv as le}from"./index-BFHZsBkN.js";import{bx as j,E as k,c as $,d as p,e as n,z as c,by as a,j as T,q as I,k as u,u as i,s as G,r as A,w as J,cp as K,h as ce,A as D,l as de}from"./vendor-other-B8t_Wf2K.js";import"./vendor-xterm-CWYFmgbN.js";import"./vendor-three-DH0o8VQ7.js";import"./vendor-tiptap-VxK0yxkd.js";const ue={key:0,class:"flex items-center gap-1"},me={class:"flex items-center gap-2"},pe={key:1,class:"flex items-center gap-1"},fe=j({__name:"UserCredit",props:{textClass:{},showCreditsOnly:{type:Boolean}},setup(h){const m=R(),x=k(()=>m.isFetchingBalance),{t:w,locale:f}=V(),v=k(()=>{const _=m.balance?.effective_balance_micros??m.balance?.amount_micros??0;return`${q({cents:_,locale:f.value})} ${w("credits.credits")}`}),d=k(()=>{const _=m.balance?.effective_balance_micros??m.balance?.amount_micros??0;return q({cents:_,locale:f.value,numberOptions:{minimumFractionDigits:0,maximumFractionDigits:0}})});return(_,g)=>x.value?(p(),$("div",ue,[n("div",me,[c(a(O),{shape:"circle",width:"1.5rem",height:"1.5rem"})]),g[0]||(g[0]=n("div",{class:"flex-1"},null,-1)),c(a(O),{width:"8rem",height:"2rem"})])):(p(),$("div",pe,[_.showCreditsOnly?I("",!0):(p(),T(a(W),{key:0,severity:"secondary",rounded:"",class:"p-1 text-amber-400"},{icon:u(()=>g[1]||(g[1]=[n("i",{class:"icon-[lucide--component]"},null,-1)])),_:1})),n("div",{class:G(_.textClass)},i(_.showCreditsOnly?d.value:v.value),3)]))}});var F=(h=>(h.CREDIT_ADDED="credit_added",h.ACCOUNT_CREATED="account_created",h.API_USAGE_STARTED="api_usage_started",h.API_USAGE_COMPLETED="api_usage_completed",h))(F||{});const M=K.create({baseURL:H(),headers:{"Content-Type":"application/json"}}),ve=l(()=>{const h=A(!1),m=A(null),{d:x}=V();J(()=>H(),e=>{M.defaults.baseURL=e});const w=l((e,s,b)=>{if(te(e))return;let y;if(!K.isAxiosError(e))y=`${s} failed: ${e instanceof Error?e.message:String(e)}`;else{const o=e,r=o.response?.status;r&&b?.[r]?y=b[r]:y=o.response?.data?.message??`${s} failed with status ${r}`}m.value=y},"handleRequestError"),f=l(async(e,s)=>{const{errorContext:b,routeSpecificErrors:y}=s;h.value=!0,m.value=null;try{return(await e()).data}catch(o){return w(o,b,y),null}finally{h.value=!1}},"executeRequest");function v(e){switch(e){case"credit_added":return"Credits Added";case"account_created":return"Account Created";case"api_usage_completed":return"API Usage";default:return e}}l(v,"formatEventType");function d(e){const s=new Date(e);return x(s,{month:"short",day:"numeric",hour:"2-digit",minute:"2-digit"})}l(d,"formatDate");function _(e){return e.split("_").map(s=>s.charAt(0).toUpperCase()+s.slice(1)).join(" ")}l(_,"formatJsonKey");function g(e){return typeof e=="number"?e.toLocaleString():typeof e=="string"&&e.match(/^\d{4}-\d{2}-\d{2}/)?new Date(e).toLocaleString():e}l(g,"formatJsonValue");function P(e){switch(e){case"credit_added":return"success";case"account_created":return"info";case"api_usage_completed":return"warning";default:return"info"}}l(P,"getEventSeverity");function E(e){const{amount:s,api_name:b,model:y,...o}=e.params||{};return Object.keys(o).length>0}l(E,"hasAdditionalInfo");function B(e){const{...s}=e.params||{};return Object.entries(s).map(([b,y])=>{const o=_(b),r=g(y);return`<strong>${o}:</strong> ${r}`}).join("<br>")}l(B,"getTooltipContent");function t(e){return e?(e/100).toFixed(2):"0.00"}l(t,"formatAmount");async function C({page:e=1,limit:s=10}={}){const b="Fetching customer events",y={400:"Invalid input, object invalid",404:"Not found"},o=await R().getAuthHeader();return o?await f(()=>M.get("/customers/events",{params:{page:e,limit:s},headers:o}),{errorContext:b,routeSpecificErrors:y}):(m.value="Authentication header is missing",null)}return l(C,"getMyEvents"),{isLoading:h,error:m,getMyEvents:C,formatEventType:v,getEventSeverity:P,formatAmount:t,hasAdditionalInfo:E,formatDate:d,formatJsonKey:_,formatJsonValue:g,getTooltipContent:B}},"useCustomerEventsService"),ge={key:0,class:"flex items-center justify-center p-8"},he={key:1,class:"p-4"},_e={class:"event-details"},ye={key:0,class:"font-semibold text-green-500"},Ce={key:1},be={key:2,class:"flex flex-col gap-1"},$e={class:"font-semibold"},xe={class:"text-sm text-smoke-400"},we=j({__name:"UsageLogsTable",setup(h,{expose:m}){const x=A([]),w=A(!0),f=A(null),v=ve(),d=A({page:1,limit:7,total:0,totalPages:0}),_=k(()=>(d.value.page-1)*d.value.limit),g=k(()=>{const t=new Map;return x.value.forEach(C=>{v.hasAdditionalInfo(C)&&C.event_id&&t.set(C.event_id,v.getTooltipContent(C))}),t}),P=l(async()=>{w.value=!0,f.value=null;try{const t=await v.getMyEvents({page:d.value.page,limit:d.value.limit});t?(t.events&&(x.value=t.events),t.page&&(d.value.page=t.page),t.limit&&(d.value.limit=t.limit),t.total&&(d.value.total=t.total),t.totalPages&&(d.value.totalPages=t.totalPages),se()?.checkForCompletedTopup(t.events)):f.value=v.error.value||"Failed to load events"}catch(t){f.value=t instanceof Error?t.message:"Unknown error",console.error("Error loading events:",t)}finally{w.value=!1}},"loadEvents"),E=l(t=>{d.value.page=t.page+1,P().catch(C=>{console.error("Error loading events:",C)})},"onPageChange");return m({refresh:l(async()=>{d.value.page=1,await P()},"refresh")}),(t,C)=>{const e=ce("tooltip");return p(),$("div",null,[w.value?(p(),$("div",ge,[c(a(X))])):f.value?(p(),$("div",he,[c(a(Y),{severity:"error",closable:!1},{default:u(()=>[D(i(f.value),1)]),_:1})])):(p(),T(a(z),{key:2,value:x.value,paginator:!0,rows:d.value.limit,"total-records":d.value.total,first:_.value,lazy:!0,class:"p-datatable-sm custom-datatable",onPage:E},{default:u(()=>[c(a(L),{field:"event_type",header:t.$t("credits.eventType")},{body:u(({data:s})=>[c(a(Z),{value:a(v).formatEventType(s.event_type),severity:a(v).getEventSeverity(s.event_type)},null,8,["value","severity"])]),_:1},8,["header"]),c(a(L),{field:"details",header:t.$t("credits.details")},{body:u(({data:s})=>[n("div",_e,[s.event_type===a(F).CREDIT_ADDED?(p(),$("div",ye,i(t.$t("credits.added"))+" $"+i(a(v).formatAmount(s.params?.amount)),1)):s.event_type===a(F).ACCOUNT_CREATED?(p(),$("div",Ce,i(t.$t("credits.accountInitialized")),1)):s.event_type===a(F).API_USAGE_COMPLETED?(p(),$("div",be,[n("div",$e,i(s.params?.api_name||"API"),1),n("div",xe,i(t.$t("credits.model"))+": "+i(s.params?.model||"-"),1)])):I("",!0)])]),_:1},8,["header"]),c(a(L),{field:"createdAt",header:t.$t("credits.time")},{body:u(({data:s})=>[D(i(a(v).formatDate(s.createdAt)),1)]),_:1},8,["header"]),c(a(L),{field:"params",header:t.$t("credits.additionalInfo")},{body:u(({data:s})=>[a(v).hasAdditionalInfo(s)?de((p(),T(S,{key:0,variant:"textonly",size:"icon-sm","aria-label":t.$t("credits.additionalInfo")},{default:u(()=>C[0]||(C[0]=[n("i",{class:"pi pi-info-circle"},null,-1)])),_:2},1032,["aria-label"])),[[e,{escape:!1,value:g.value.get(s.event_id)||"",pt:{text:{style:{width:"max-content !important"}}}},void 0,{top:!0}]]):I("",!0)]),_:1},8,["header"])]),_:1},8,["value","rows","total-records","first"]))])}}}),Ae={class:"flex h-full flex-col"},ke={class:"mb-2 text-2xl font-bold"},Ee={class:"flex flex-col gap-2"},Se={class:"text-sm font-medium text-muted"},De={class:"flex items-center justify-between"},Te={class:"flex flex-row items-center"},Pe={key:1,class:"text-xs text-muted"},Ue={class:"flex items-center justify-between"},Le={key:0,class:"grow"},Ie={class:"text-sm font-medium"},Be={class:"text-xs text-muted"},Fe={class:"flex flex-row gap-2"},He=j({__name:"LegacyCreditsPanel",setup(h){const{buildDocsUrl:m,docsPaths:x}=ae(),w=oe(),f=R(),v=ne(),d=ie(),{isActiveSubscription:_}=re(),g=k(()=>f.loading),P=k(()=>f.isFetchingBalance),E=A(null),B=k(()=>f.lastBalanceUpdateTime?f.lastBalanceUpdateTime.toLocaleString():"");J(()=>f.lastBalanceUpdateTime,(o,r)=>{o&&o!==r&&E.value&&E.value.refresh()});const t=l(()=>{w.showTopUpCreditsDialog()},"handlePurchaseCreditsClick"),C=l(async()=>{await v.accessBillingPortal()},"handleCreditsHistoryClick"),e=l(async()=>{await d.execute("Comfy.ContactSupport")},"handleMessageSupport"),s=l(()=>{window.open(m("/tutorials/api-nodes/faq",{includeLocale:!0}),"_blank")},"handleFaqClick"),b=l(()=>{window.open(m(x.partnerNodesPricing,{includeLocale:!0}),"_blank")},"handleOpenPartnerNodesInfo"),y=A([]);return(o,r)=>(p(),T(a(ee),{value:"Credits",class:"credits-container h-full"},{default:u(()=>[n("div",Ae,[n("h2",ke,i(o.$t("credits.credits")),1),c(a(N)),n("div",Ee,[n("h3",Se,i(o.$t("credits.yourCreditBalance")),1),n("div",De,[c(fe,{"text-class":"text-3xl font-bold"}),g.value?(p(),T(a(O),{key:0,width:"2rem",height:"2rem"})):a(_)?(p(),T(S,{key:1,loading:g.value,onClick:t},{default:u(()=>[D(i(o.$t("credits.purchaseCredits")),1)]),_:1},8,["loading"])):I("",!0)]),n("div",Te,[P.value?(p(),T(a(O),{key:0,width:"12rem",height:"1rem",class:"text-xs"})):B.value?(p(),$("div",Pe,i(o.$t("credits.lastUpdated"))+": "+i(B.value),1)):I("",!0),c(S,{variant:"muted-textonly",size:"icon-sm","aria-label":o.$t("g.refresh"),onClick:r[0]||(r[0]=()=>a(v).fetchBalance())},{default:u(()=>r[1]||(r[1]=[n("i",{class:"pi pi-refresh"},null,-1)])),_:1},8,["aria-label"])])]),n("div",Ue,[n("h3",null,i(o.$t("credits.activity")),1),c(S,{variant:"muted-textonly",loading:g.value,onClick:C},{default:u(()=>[r[2]||(r[2]=n("i",{class:"pi pi-arrow-up-right"},null,-1)),D(" "+i(o.$t("credits.invoiceHistory")),1)]),_:1},8,["loading"])]),y.value.length>0?(p(),$("div",Le,[c(a(z),{value:y.value,"show-headers":!1},{default:u(()=>[c(a(L),{field:"title",header:o.$t("g.name")},{body:u(({data:U})=>[n("div",Ie,i(U.title),1),n("div",Be,i(U.timestamp),1)]),_:1},8,["header"]),c(a(L),{field:"amount",header:o.$t("g.amount")},{body:u(({data:U})=>[n("div",{class:G(["text-center text-base font-medium",U.isPositive?"text-sky-500":"text-red-400"])},i(U.isPositive?"+":"-")+"$"+i(a(le)(U.amount,"usd")),3)]),_:1},8,["header"])]),_:1},8,["value"])])):I("",!0),c(a(N)),c(we,{ref_key:"usageLogsTableRef",ref:E},null,512),n("div",Fe,[c(S,{variant:"muted-textonly",onClick:s},{default:u(()=>[r[3]||(r[3]=n("i",{class:"pi pi-question-circle"},null,-1)),D(" "+i(o.$t("credits.faqs")),1)]),_:1}),c(S,{variant:"muted-textonly",onClick:b},{default:u(()=>[r[4]||(r[4]=n("i",{class:"pi pi-question-circle"},null,-1)),D(" "+i(o.$t("subscription.partnerNodesCredits")),1)]),_:1}),c(S,{variant:"muted-textonly",onClick:e},{default:u(()=>[r[5]||(r[5]=n("i",{class:"pi pi-comments"},null,-1)),D(" "+i(o.$t("credits.messageSupport")),1)]),_:1})])])]),_:1}))}});export{He as default};
2
+ //# sourceMappingURL=LegacyCreditsPanel-CO0JRKfg.js.map