katello 4.17.0 → 4.18.0.rc1

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.

Potentially problematic release.


This version of katello might be problematic. Click here for more details.

Files changed (299) hide show
  1. checksums.yaml +4 -4
  2. data/app/assets/javascripts/katello/locale/bn/katello.js +148 -4
  3. data/app/assets/javascripts/katello/locale/bn_IN/katello.js +148 -4
  4. data/app/assets/javascripts/katello/locale/ca/katello.js +148 -4
  5. data/app/assets/javascripts/katello/locale/cs/katello.js +148 -4
  6. data/app/assets/javascripts/katello/locale/cs_CZ/katello.js +148 -4
  7. data/app/assets/javascripts/katello/locale/de/katello.js +147 -3
  8. data/app/assets/javascripts/katello/locale/de_AT/katello.js +148 -4
  9. data/app/assets/javascripts/katello/locale/de_DE/katello.js +148 -4
  10. data/app/assets/javascripts/katello/locale/el/katello.js +148 -4
  11. data/app/assets/javascripts/katello/locale/en/katello.js +148 -4
  12. data/app/assets/javascripts/katello/locale/en_GB/katello.js +148 -4
  13. data/app/assets/javascripts/katello/locale/en_US/katello.js +148 -4
  14. data/app/assets/javascripts/katello/locale/es/katello.js +147 -3
  15. data/app/assets/javascripts/katello/locale/et_EE/katello.js +148 -4
  16. data/app/assets/javascripts/katello/locale/fr/katello.js +147 -3
  17. data/app/assets/javascripts/katello/locale/gl/katello.js +148 -4
  18. data/app/assets/javascripts/katello/locale/gu/katello.js +148 -4
  19. data/app/assets/javascripts/katello/locale/he_IL/katello.js +148 -4
  20. data/app/assets/javascripts/katello/locale/hi/katello.js +148 -4
  21. data/app/assets/javascripts/katello/locale/id/katello.js +148 -4
  22. data/app/assets/javascripts/katello/locale/it/katello.js +148 -4
  23. data/app/assets/javascripts/katello/locale/ja/katello.js +147 -3
  24. data/app/assets/javascripts/katello/locale/ka/katello.js +147 -3
  25. data/app/assets/javascripts/katello/locale/kn/katello.js +148 -4
  26. data/app/assets/javascripts/katello/locale/ko/katello.js +147 -3
  27. data/app/assets/javascripts/katello/locale/ml_IN/katello.js +148 -4
  28. data/app/assets/javascripts/katello/locale/mr/katello.js +148 -4
  29. data/app/assets/javascripts/katello/locale/nl_NL/katello.js +148 -4
  30. data/app/assets/javascripts/katello/locale/or/katello.js +148 -4
  31. data/app/assets/javascripts/katello/locale/pa/katello.js +148 -4
  32. data/app/assets/javascripts/katello/locale/pl/katello.js +148 -4
  33. data/app/assets/javascripts/katello/locale/pl_PL/katello.js +148 -4
  34. data/app/assets/javascripts/katello/locale/pt/katello.js +148 -4
  35. data/app/assets/javascripts/katello/locale/pt_BR/katello.js +147 -3
  36. data/app/assets/javascripts/katello/locale/ro/katello.js +148 -4
  37. data/app/assets/javascripts/katello/locale/ro_RO/katello.js +148 -4
  38. data/app/assets/javascripts/katello/locale/ru/katello.js +148 -4
  39. data/app/assets/javascripts/katello/locale/sl/katello.js +148 -4
  40. data/app/assets/javascripts/katello/locale/sv_SE/katello.js +148 -4
  41. data/app/assets/javascripts/katello/locale/ta/katello.js +148 -4
  42. data/app/assets/javascripts/katello/locale/ta_IN/katello.js +148 -4
  43. data/app/assets/javascripts/katello/locale/te/katello.js +148 -4
  44. data/app/assets/javascripts/katello/locale/tr/katello.js +148 -4
  45. data/app/assets/javascripts/katello/locale/vi/katello.js +148 -4
  46. data/app/assets/javascripts/katello/locale/vi_VN/katello.js +148 -4
  47. data/app/assets/javascripts/katello/locale/zh/katello.js +148 -4
  48. data/app/assets/javascripts/katello/locale/zh_CN/katello.js +147 -3
  49. data/app/assets/javascripts/katello/locale/zh_TW/katello.js +148 -4
  50. data/app/controllers/katello/api/registry/registry_proxies_controller.rb +14 -14
  51. data/app/controllers/katello/api/v2/content_uploads_controller.rb +2 -1
  52. data/app/controllers/katello/api/v2/errata_controller.rb +16 -0
  53. data/app/controllers/katello/api/v2/flatpak_remote_repositories_controller.rb +20 -3
  54. data/app/controllers/katello/api/v2/flatpak_remotes_controller.rb +7 -3
  55. data/app/controllers/katello/api/v2/generic_content_units_controller.rb +1 -2
  56. data/app/controllers/katello/api/v2/products_controller.rb +18 -0
  57. data/app/controllers/katello/api/v2/repositories_controller.rb +5 -3
  58. data/app/controllers/katello/concerns/api/v2/hosts_bulk_actions_controller_extensions.rb +10 -0
  59. data/app/controllers/katello/concerns/api/v2/registration_commands_controller_extensions.rb +1 -0
  60. data/app/controllers/katello/concerns/filtered_auto_complete_search.rb +17 -0
  61. data/app/lib/actions/helpers/smart_proxy_sync_helper.rb +12 -0
  62. data/app/lib/actions/katello/content_view/add_rolling_repo_clone.rb +4 -4
  63. data/app/lib/actions/katello/content_view/capsule_sync.rb +8 -3
  64. data/app/lib/actions/katello/content_view/publish.rb +39 -12
  65. data/app/lib/actions/katello/flatpak/mirror_remote_repository.rb +2 -1
  66. data/app/lib/actions/katello/repository/capsule_sync.rb +11 -1
  67. data/app/lib/actions/katello/repository/destroy.rb +3 -0
  68. data/app/lib/actions/katello/repository/import_upload.rb +2 -3
  69. data/app/lib/actions/katello/repository/sync.rb +2 -1
  70. data/app/lib/actions/katello/repository/upload_files.rb +2 -1
  71. data/app/lib/katello/concerns/bookmark_controller_validator_extensions.rb +1 -1
  72. data/app/lib/katello/resources/cdn.rb +1 -1
  73. data/app/models/katello/concerns/smart_proxy_extensions.rb +46 -8
  74. data/app/models/katello/content_view_environment.rb +1 -1
  75. data/app/models/katello/erratum.rb +26 -1
  76. data/app/models/katello/flatpak_remote.rb +0 -1
  77. data/app/models/katello/flatpak_remote_repository.rb +24 -0
  78. data/app/models/katello/glue/pulp/repos.rb +1 -1
  79. data/app/models/katello/root_repository.rb +1 -0
  80. data/app/presenters/katello/flatpak_remote_mirror_status_presenter.rb +41 -0
  81. data/app/services/katello/repository_type_manager.rb +2 -0
  82. data/app/views/foreman/job_templates/flatpak_install.erb +17 -2
  83. data/app/views/foreman/job_templates/flatpak_login_action.erb +17 -3
  84. data/app/views/foreman/job_templates/install_errata_by_search_query.erb +1 -1
  85. data/app/views/foreman/job_templates/install_errata_by_search_query_-_katello_ansible_default.erb +1 -1
  86. data/app/views/foreman/job_templates/install_packages_by_search_query_-_katello_ansible_default.erb +6 -14
  87. data/app/views/foreman/job_templates/remove_packages_by_search_query_-_katello_ansible_default.erb +2 -15
  88. data/app/views/foreman/job_templates/update_packages_by_search_query_-_katello_ansible_default.erb +5 -13
  89. data/app/views/katello/api/v2/flatpak_remote_repositories/base.json.rabl +3 -1
  90. data/app/views/katello/api/v2/flatpak_remotes/base.json.rabl +5 -0
  91. data/app/views/katello/api/v2/flatpak_remotes/permissions.json.rabl +1 -0
  92. data/config/routes/api/v2.rb +1 -1
  93. data/config/routes.rb +3 -0
  94. data/db/migrate/20240924161240_katello_recreate_evr_constructs.rb +20 -0
  95. data/db/migrate/20250613210050_use_big_int_for_erratum_packages_id.rb +11 -0
  96. data/db/migrate/20250714190050_add_missing_rpms_evr_index.rb +14 -0
  97. data/db/seeds.d/108-subcription-bookmarks.rb +2 -0
  98. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/content-hosts/views/content-hosts.html +1 -1
  99. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/errata/views/errata.html +5 -1
  100. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/i18n/bastion_katello.pot +4 -5
  101. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/i18n/locale/bn.po +6 -0
  102. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/i18n/locale/bn_IN.po +6 -0
  103. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/i18n/locale/ca.po +6 -0
  104. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/i18n/locale/cs_CZ.po +6 -0
  105. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/i18n/locale/de.po +6 -0
  106. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/i18n/locale/de_AT.po +6 -0
  107. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/i18n/locale/de_DE.po +6 -0
  108. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/i18n/locale/el.po +6 -0
  109. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/i18n/locale/en_GB.po +6 -0
  110. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/i18n/locale/en_US.po +6 -0
  111. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/i18n/locale/es.po +6 -0
  112. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/i18n/locale/et_EE.po +6 -0
  113. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/i18n/locale/fr.po +6 -0
  114. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/i18n/locale/gl.po +6 -0
  115. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/i18n/locale/gu.po +6 -0
  116. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/i18n/locale/he_IL.po +6 -0
  117. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/i18n/locale/hi.po +6 -0
  118. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/i18n/locale/id.po +6 -0
  119. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/i18n/locale/it.po +6 -0
  120. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/i18n/locale/ja.po +6 -0
  121. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/i18n/locale/ka.po +6 -0
  122. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/i18n/locale/kn.po +6 -0
  123. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/i18n/locale/ko.po +6 -0
  124. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/i18n/locale/ml_IN.po +6 -0
  125. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/i18n/locale/mr.po +6 -0
  126. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/i18n/locale/nl_NL.po +6 -0
  127. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/i18n/locale/or.po +6 -0
  128. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/i18n/locale/pa.po +6 -0
  129. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/i18n/locale/pl.po +6 -0
  130. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/i18n/locale/pl_PL.po +6 -0
  131. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/i18n/locale/pt.po +6 -0
  132. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/i18n/locale/pt_BR.po +6 -0
  133. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/i18n/locale/ro.po +6 -0
  134. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/i18n/locale/ro_RO.po +6 -0
  135. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/i18n/locale/ru.po +6 -0
  136. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/i18n/locale/sl.po +6 -0
  137. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/i18n/locale/sv_SE.po +6 -0
  138. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/i18n/locale/ta.po +6 -0
  139. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/i18n/locale/ta_IN.po +6 -0
  140. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/i18n/locale/te.po +6 -0
  141. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/i18n/locale/tr.po +6 -0
  142. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/i18n/locale/vi.po +6 -0
  143. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/i18n/locale/vi_VN.po +6 -0
  144. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/i18n/locale/zh.po +6 -0
  145. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/i18n/locale/zh_CN.po +6 -0
  146. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/i18n/locale/zh_TW.po +6 -0
  147. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/products/details/repositories/new/new-repository.controller.js +13 -3
  148. data/engines/bastion_katello/lib/bastion_katello/engine.rb +2 -0
  149. data/lib/katello/engine.rb +0 -1
  150. data/lib/katello/permission_creator.rb +1 -1
  151. data/lib/katello/plugin.rb +26 -2
  152. data/lib/katello/version.rb +1 -1
  153. data/lib/katello.rb +0 -1
  154. data/lib/proxy_api/container_gateway.rb +24 -0
  155. data/locale/bn/LC_MESSAGES/katello.mo +0 -0
  156. data/locale/bn/katello.po +148 -4
  157. data/locale/bn_IN/LC_MESSAGES/katello.mo +0 -0
  158. data/locale/bn_IN/katello.po +148 -4
  159. data/locale/ca/LC_MESSAGES/katello.mo +0 -0
  160. data/locale/ca/katello.po +148 -4
  161. data/locale/cs/LC_MESSAGES/katello.mo +0 -0
  162. data/locale/cs/katello.po +148 -4
  163. data/locale/cs_CZ/LC_MESSAGES/katello.mo +0 -0
  164. data/locale/cs_CZ/katello.po +148 -4
  165. data/locale/de/katello.po +147 -3
  166. data/locale/de_AT/LC_MESSAGES/katello.mo +0 -0
  167. data/locale/de_AT/katello.po +148 -4
  168. data/locale/de_DE/LC_MESSAGES/katello.mo +0 -0
  169. data/locale/de_DE/katello.po +148 -4
  170. data/locale/el/LC_MESSAGES/katello.mo +0 -0
  171. data/locale/el/katello.po +148 -4
  172. data/locale/en/LC_MESSAGES/katello.mo +0 -0
  173. data/locale/en/katello.po +148 -4
  174. data/locale/en_GB/LC_MESSAGES/katello.mo +0 -0
  175. data/locale/en_GB/katello.po +148 -4
  176. data/locale/en_US/LC_MESSAGES/katello.mo +0 -0
  177. data/locale/en_US/katello.po +148 -4
  178. data/locale/es/katello.po +147 -3
  179. data/locale/et_EE/LC_MESSAGES/katello.mo +0 -0
  180. data/locale/et_EE/katello.po +148 -4
  181. data/locale/fr/katello.po +147 -3
  182. data/locale/gl/LC_MESSAGES/katello.mo +0 -0
  183. data/locale/gl/katello.po +148 -4
  184. data/locale/gu/LC_MESSAGES/katello.mo +0 -0
  185. data/locale/gu/katello.po +148 -4
  186. data/locale/he_IL/LC_MESSAGES/katello.mo +0 -0
  187. data/locale/he_IL/katello.po +148 -4
  188. data/locale/hi/LC_MESSAGES/katello.mo +0 -0
  189. data/locale/hi/katello.po +148 -4
  190. data/locale/id/LC_MESSAGES/katello.mo +0 -0
  191. data/locale/id/katello.po +148 -4
  192. data/locale/it/LC_MESSAGES/katello.mo +0 -0
  193. data/locale/it/katello.po +148 -4
  194. data/locale/ja/katello.po +147 -3
  195. data/locale/ka/katello.po +147 -3
  196. data/locale/katello.pot +703 -428
  197. data/locale/kn/LC_MESSAGES/katello.mo +0 -0
  198. data/locale/kn/katello.po +148 -4
  199. data/locale/ko/katello.po +147 -3
  200. data/locale/ml_IN/LC_MESSAGES/katello.mo +0 -0
  201. data/locale/ml_IN/katello.po +148 -4
  202. data/locale/mr/LC_MESSAGES/katello.mo +0 -0
  203. data/locale/mr/katello.po +148 -4
  204. data/locale/nl_NL/LC_MESSAGES/katello.mo +0 -0
  205. data/locale/nl_NL/katello.po +148 -4
  206. data/locale/or/LC_MESSAGES/katello.mo +0 -0
  207. data/locale/or/katello.po +148 -4
  208. data/locale/pa/LC_MESSAGES/katello.mo +0 -0
  209. data/locale/pa/katello.po +148 -4
  210. data/locale/pl/LC_MESSAGES/katello.mo +0 -0
  211. data/locale/pl/katello.po +148 -4
  212. data/locale/pl_PL/LC_MESSAGES/katello.mo +0 -0
  213. data/locale/pl_PL/katello.po +148 -4
  214. data/locale/pt/LC_MESSAGES/katello.mo +0 -0
  215. data/locale/pt/katello.po +148 -4
  216. data/locale/pt_BR/katello.po +147 -3
  217. data/locale/ro/LC_MESSAGES/katello.mo +0 -0
  218. data/locale/ro/katello.po +148 -4
  219. data/locale/ro_RO/LC_MESSAGES/katello.mo +0 -0
  220. data/locale/ro_RO/katello.po +148 -4
  221. data/locale/ru/LC_MESSAGES/katello.mo +0 -0
  222. data/locale/ru/katello.po +148 -4
  223. data/locale/sl/LC_MESSAGES/katello.mo +0 -0
  224. data/locale/sl/katello.po +148 -4
  225. data/locale/sv_SE/LC_MESSAGES/katello.mo +0 -0
  226. data/locale/sv_SE/katello.po +148 -4
  227. data/locale/ta/LC_MESSAGES/katello.mo +0 -0
  228. data/locale/ta/katello.po +148 -4
  229. data/locale/ta_IN/LC_MESSAGES/katello.mo +0 -0
  230. data/locale/ta_IN/katello.po +148 -4
  231. data/locale/te/LC_MESSAGES/katello.mo +0 -0
  232. data/locale/te/katello.po +148 -4
  233. data/locale/tr/LC_MESSAGES/katello.mo +0 -0
  234. data/locale/tr/katello.po +148 -4
  235. data/locale/vi/LC_MESSAGES/katello.mo +0 -0
  236. data/locale/vi/katello.po +148 -4
  237. data/locale/vi_VN/LC_MESSAGES/katello.mo +0 -0
  238. data/locale/vi_VN/katello.po +148 -4
  239. data/locale/zh/LC_MESSAGES/katello.mo +0 -0
  240. data/locale/zh/katello.po +148 -4
  241. data/locale/zh_CN/katello.po +147 -3
  242. data/locale/zh_TW/LC_MESSAGES/katello.mo +0 -0
  243. data/locale/zh_TW/katello.po +148 -4
  244. data/package.json +0 -1
  245. data/webpack/components/Content/Details/__tests__/__snapshots__/ContentDetails.test.js.snap +2 -2
  246. data/webpack/components/OptionTooltip/OptionTooltip.scss +1 -1
  247. data/webpack/components/extensions/HostDetails/Tabs/PackagesTab/PackagesTab.js +6 -1
  248. data/webpack/components/extensions/Hosts/ActionsBar/index.js +11 -0
  249. data/webpack/components/extensions/Hosts/BulkActions/BulkChangeHostCVModal/BulkChangeHostCVModal.js +1 -1
  250. data/webpack/components/extensions/Hosts/BulkActions/BulkChangeHostCVModal/actions.js +1 -2
  251. data/webpack/components/extensions/Hosts/BulkActions/BulkErrataWizard/04_ReviewFooter.js +1 -1
  252. data/webpack/components/extensions/Hosts/BulkActions/BulkPackagesWizard/04_ReviewFooter.js +1 -1
  253. data/webpack/components/extensions/Hosts/BulkActions/BulkRepositorySetsWizard/01_BulkRepositorySetsTable.js +371 -0
  254. data/webpack/components/extensions/Hosts/BulkActions/BulkRepositorySetsWizard/03_Review.js +79 -0
  255. data/webpack/components/extensions/Hosts/BulkActions/BulkRepositorySetsWizard/03_ReviewFooter.js +73 -0
  256. data/webpack/components/extensions/Hosts/BulkActions/BulkRepositorySetsWizard/BulkRepositorySetsWizard.js +170 -0
  257. data/webpack/components/extensions/Hosts/BulkActions/BulkRepositorySetsWizard/actions.js +23 -0
  258. data/webpack/components/extensions/Hosts/BulkActions/BulkRepositorySetsWizard/helpers.js +28 -0
  259. data/webpack/components/extensions/Hosts/BulkActions/BulkRepositorySetsWizard/index.js +23 -0
  260. data/webpack/components/extensions/RegistrationCommands/fields/SetupContainerRegistryCerts.js +39 -0
  261. data/webpack/components/extensions/RegistrationCommands/index.js +7 -0
  262. data/webpack/components/pf3Table/formatters/ellipsisCellFormatter.js +3 -2
  263. data/webpack/containers/Application/config.js +11 -0
  264. data/webpack/global_index.js +3 -1
  265. data/webpack/scenes/FlatpakRemotes/CreateEdit/CreateFlatpakRemoteModal.js +30 -0
  266. data/webpack/scenes/FlatpakRemotes/CreateEdit/EditFlatpakRemotesModal.js +38 -0
  267. data/webpack/scenes/FlatpakRemotes/CreateEdit/FlatpakRemoteform.js +218 -0
  268. data/webpack/scenes/FlatpakRemotes/CreateEdit/__tests__/flatpakRemoteform.test.js +117 -0
  269. data/webpack/scenes/FlatpakRemotes/Delete/DeleteFlatpakModal.js +59 -0
  270. data/webpack/scenes/FlatpakRemotes/Details/FlatpakRemoteDetailActions.js +87 -0
  271. data/webpack/scenes/FlatpakRemotes/Details/FlatpakRemoteDetailReducers.js +23 -0
  272. data/webpack/scenes/FlatpakRemotes/Details/FlatpakRemoteDetailSelectors.js +16 -0
  273. data/webpack/scenes/FlatpakRemotes/Details/FlatpakRemoteDetails.js +167 -0
  274. data/webpack/scenes/FlatpakRemotes/Details/Mirror/MirrorRepositoryModal.js +135 -0
  275. data/webpack/scenes/FlatpakRemotes/Details/Mirror/__tests__/mirrorRepositoryModal.test.js +167 -0
  276. data/webpack/scenes/FlatpakRemotes/Details/RemoteRepositories/RemoteRepositoriesTable.js +171 -0
  277. data/webpack/scenes/FlatpakRemotes/Details/__tests__/flatpakRemoteDetails.fixtures.json +58 -0
  278. data/webpack/scenes/FlatpakRemotes/Details/__tests__/flatpakRemoteDetails.test.js +90 -0
  279. data/webpack/scenes/FlatpakRemotes/Details/index.js +4 -0
  280. data/webpack/scenes/FlatpakRemotes/FlatpakRemotesActions.js +26 -0
  281. data/webpack/scenes/FlatpakRemotes/FlatpakRemotesConstants.js +15 -0
  282. data/webpack/scenes/FlatpakRemotes/FlatpakRemotesPage.js +202 -0
  283. data/webpack/scenes/FlatpakRemotes/FlatpakRemotesSelectors.js +24 -0
  284. data/webpack/scenes/FlatpakRemotes/__tests__/flatpakRemotesList.fixtures.json +55 -0
  285. data/webpack/scenes/FlatpakRemotes/__tests__/flatpakRemotesPage.test.js +74 -0
  286. data/webpack/scenes/FlatpakRemotes/index.js +4 -0
  287. data/webpack/scenes/Hosts/ChangeContentSource/components/Hosts.js +2 -2
  288. data/webpack/scenes/RedHatRepositories/components/RecommendedRepositorySetsToggler.scss +1 -1
  289. data/webpack/scenes/RedHatRepositories/index.scss +1 -1
  290. data/webpack/scenes/Settings/SettingsSelectors.js +3 -3
  291. data/webpack/scenes/Settings/index.js +1 -3
  292. data/webpack/scenes/Subscriptions/Details/__tests__/__snapshots__/SubscriptionDetails.test.js.snap +2 -2
  293. data/webpack/scenes/Subscriptions/SubscriptionsPage.scss +1 -1
  294. data/webpack/scenes/Subscriptions/__tests__/SubscriptionsReducer.test.js +0 -21
  295. data/webpack/scenes/Subscriptions/__tests__/__snapshots__/SubscriptionsReducer.test.js.snap +0 -44
  296. data/webpack/scenes/Subscriptions/index.js +1 -3
  297. metadata +39 -21
  298. data/webpack/scenes/Settings/SettingsConstants.js +0 -2
  299. data/webpack/scenes/Settings/SettingsReducer.js +0 -19
@@ -0,0 +1,371 @@
1
+ import React, { useState, useContext } from 'react';
2
+ import PropTypes from 'prop-types';
3
+ import {
4
+ Alert, Dropdown, DropdownItem, DropdownList,
5
+ Divider, MenuToggle, MenuToggleAction, ToolbarItem,
6
+ } from '@patternfly/react-core';
7
+ import {
8
+ Tr, Td, Tbody,
9
+ } from '@patternfly/react-table';
10
+ import { STATUS } from 'foremanReact/constants';
11
+ import { useForemanOrganization } from 'foremanReact/Root/Context/ForemanContext';
12
+ import { getPageStats, getColumnHelpers } from 'foremanReact/components/PF4/TableIndexPage/Table/helpers';
13
+ import { useSet } from 'foremanReact/components/PF4/TableIndexPage/Table/TableHooks';
14
+ import TableIndexPage from 'foremanReact/components/PF4/TableIndexPage/TableIndexPage';
15
+ import { Table } from 'foremanReact/components/PF4/TableIndexPage/Table/Table';
16
+ import { translate as __ } from 'foremanReact/common/I18n';
17
+ import { RowSelectTd } from 'foremanReact/components/HostsIndex/RowSelectTd';
18
+ import SelectAllCheckbox from 'foremanReact/components/PF4/TableIndexPage/Table/SelectAllCheckbox';
19
+ import { noop } from 'foremanReact/common/helpers';
20
+
21
+ import katelloApi from '../../../../../services/api';
22
+ import { repoSetsUrlForOrg, BulkRepositorySetsWizardContext } from './BulkRepositorySetsWizard';
23
+
24
+ export const dropdownValues = {
25
+ 0: __('No change'),
26
+ 1: __('Override to enabled'),
27
+ 2: __('Override to disabled'),
28
+ 3: __('Reset to default'),
29
+ };
30
+
31
+ const ContentOverrideDropdown =
32
+ ({
33
+ repoLabel, pendingOverrides, setPendingOverrides, setShouldValidateStep1,
34
+ }) => {
35
+ const [isOpen, setIsOpen] = useState(false);
36
+
37
+ const currentValue = pendingOverrides[repoLabel] ?? 0;
38
+ const currentLabel = dropdownValues[currentValue];
39
+ const onToggleClick = () => {
40
+ setIsOpen(!isOpen);
41
+ };
42
+ const onSelect = (_event, value) => {
43
+ setIsOpen(false);
44
+ setShouldValidateStep1(true);
45
+ setPendingOverrides({
46
+ ...pendingOverrides,
47
+ [repoLabel]: value,
48
+ });
49
+ };
50
+ return (
51
+ <Dropdown
52
+ key={`pf-ContentOverrideDropdown-${repoLabel}`}
53
+ isOpen={isOpen}
54
+ onSelect={onSelect}
55
+ onOpenChange={openVal => setIsOpen(!openVal)}
56
+ toggle={toggleRef => (
57
+ <MenuToggle ref={toggleRef} onClick={onToggleClick} isExpanded={isOpen}>
58
+ {currentLabel}
59
+ </MenuToggle>)}
60
+ ouiaId={`ContentOverrideDropdown-${repoLabel}`}
61
+ shouldFocusToggleOnSelect
62
+ >
63
+ <DropdownList>
64
+ <DropdownItem value={0} key={`content-override-dropdown-${repoLabel}-no-change`} ouiaId={`content-override-dropdown-${repoLabel}-no-change`}>
65
+ {__('No change')}
66
+ </DropdownItem>
67
+ <DropdownItem value={1} key={`content-override-dropdown-${repoLabel}-enable`} ouiaId={`content-override-dropdown-${repoLabel}-enable`}>
68
+ {__('Override to enabled')}
69
+ </DropdownItem>
70
+ <DropdownItem value={2} key={`content-override-dropdown-${repoLabel}-disable`} ouiaId={`content-override-dropdown-${repoLabel}-disable`}>
71
+ {__('Override to disabled')}
72
+ </DropdownItem>
73
+ <Divider key="divider" />
74
+ <DropdownItem value={3} key={`content-override-dropdown-${repoLabel}-reset-to-default`} ouiaId={`content-override-dropdown-${repoLabel}-reset-to-default`}>
75
+ {__('Reset to default')}
76
+ </DropdownItem>
77
+ </DropdownList>
78
+ </Dropdown>
79
+ );
80
+ };
81
+
82
+ ContentOverrideDropdown.propTypes = {
83
+ repoLabel: PropTypes.string.isRequired,
84
+ pendingOverrides: PropTypes.shape({
85
+ [PropTypes.string]: PropTypes.number,
86
+ }).isRequired,
87
+ setPendingOverrides: PropTypes.func.isRequired,
88
+ setShouldValidateStep1: PropTypes.func.isRequired,
89
+ };
90
+
91
+ export const BulkRepositorySetsTable = ({
92
+ repoSetsBulkSelect,
93
+ repoSetsResults,
94
+ repoSetsMetadata,
95
+ repoSetsResponse,
96
+ }) => {
97
+ const {
98
+ selectPage,
99
+ selectNone,
100
+ selectOne,
101
+ isSelected,
102
+ selectedCount,
103
+ selectedResults,
104
+ areAllRowsSelected,
105
+ areAllRowsOnPageSelected,
106
+ updateSearchQuery,
107
+ } = repoSetsBulkSelect;
108
+
109
+ const repoSetsWizardContext = useContext(BulkRepositorySetsWizardContext);
110
+ const {
111
+ pendingOverrides, setPendingOverrides, shouldValidateStep1,
112
+ setShouldValidateStep1, repoSetsSelectionIsValid,
113
+ setRepoSetsParamsAndAPI,
114
+ } = repoSetsWizardContext;
115
+ const orgId = useForemanOrganization()?.id;
116
+ const [actionDropdownValue, setActionDropdownValue] = useState(0);
117
+ const [actionToggleOpen, setActionToggleOpen] = useState(false);
118
+
119
+ const {
120
+ total, page, subtotal, per_page: perPage,
121
+ } = repoSetsMetadata;
122
+ const apiOptions = { key: 'BULK_HOST_REPO_SETS' };
123
+ const { status: repoSetsLoadingStatus } = repoSetsResponse;
124
+ const pageStats = getPageStats({ total: subtotal, page, perPage });
125
+
126
+ const expandedRepos = useSet([]);
127
+ const repoIsExpanded = id => expandedRepos.has(id);
128
+
129
+ const columns = {
130
+ name: {
131
+ title: __('Name'),
132
+ wrapper: (repo) => {
133
+ const productId = repo?.product?.id;
134
+ const href = `/products/${productId}/repositories/`;
135
+ return (
136
+ <a target="_blank" href={href} rel="noreferrer">{repo.name}</a>
137
+ );
138
+ },
139
+ isSorted: true,
140
+ weight: 50,
141
+ },
142
+ enabled_by_default: {
143
+ title: __('Status'),
144
+ wrapper: ({ label }) => (
145
+ <ContentOverrideDropdown
146
+ key={label ?? 'no-label'}
147
+ repoLabel={label}
148
+ pendingOverrides={pendingOverrides}
149
+ setPendingOverrides={setPendingOverrides}
150
+ setShouldValidateStep1={setShouldValidateStep1}
151
+ />
152
+ ),
153
+ isSorted: false,
154
+ weight: 100,
155
+ },
156
+ };
157
+
158
+ const selectionToolbar = (
159
+ <ToolbarItem key="selectAll">
160
+ <SelectAllCheckbox
161
+ {...{
162
+ selectAll: noop,
163
+ selectOne,
164
+ updateSearchQuery,
165
+ selectNone,
166
+ selectPage,
167
+ selectedCount,
168
+ pageRowCount: pageStats.pageRowCount,
169
+ areAllRowsSelected,
170
+ areAllRowsOnPageSelected,
171
+ }}
172
+ totalCount={total}
173
+ areAllRowsOnPageSelected={areAllRowsOnPageSelected()}
174
+ areAllRowsSelected={areAllRowsSelected()}
175
+ />
176
+ </ToolbarItem>
177
+ );
178
+
179
+ const onToggleClick = () => {
180
+ setActionToggleOpen(!actionToggleOpen);
181
+ };
182
+ const handleActionToggle = (value) => {
183
+ const result = {};
184
+ selectedResults.forEach((repo) => {
185
+ result[repo.label] = value;
186
+ });
187
+ setPendingOverrides({ ...pendingOverrides, ...result });
188
+ setShouldValidateStep1(true);
189
+ };
190
+ const onSelect = (_event, value) => {
191
+ handleActionToggle(value);
192
+ setActionToggleOpen(false);
193
+ };
194
+
195
+ const actionButton = (
196
+ <Dropdown
197
+ isOpen={actionToggleOpen}
198
+ onSelect={onSelect}
199
+ onOpenChange={val => setActionToggleOpen(!val)}
200
+ key="content-override-action-dropdown"
201
+ ouiaId="content-override-action-dropdown"
202
+ toggle={toggleRef => (
203
+ <MenuToggle
204
+ ref={toggleRef}
205
+ onClick={onToggleClick}
206
+ isExpanded={actionToggleOpen}
207
+ variant="primary"
208
+ splitButtonOptions={{
209
+ variant: 'action',
210
+ items: [
211
+ <MenuToggleAction
212
+ isDisabled={selectedCount === 0}
213
+ id="split-button-action-example-with-toggle-button"
214
+ key="split-action"
215
+ aria-label="Action"
216
+ onClick={() => handleActionToggle(actionDropdownValue)}
217
+ >
218
+ {dropdownValues[actionDropdownValue]}
219
+ </MenuToggleAction>],
220
+ }}
221
+ aria-label="Content override action to apply to all selected repositories"
222
+ isDisabled={selectedCount === 0}
223
+ />
224
+ )}
225
+ >
226
+ <DropdownList>
227
+ {Object.entries(dropdownValues).map(([key, value]) => (
228
+ <DropdownItem
229
+ key={key}
230
+ value={key}
231
+ ouiaId={`content-override-action-dropdown-${key}`}
232
+ onClick={() => setActionDropdownValue(key)}
233
+ >
234
+ {value}
235
+ </DropdownItem>
236
+ ))}
237
+ </DropdownList>
238
+ </Dropdown>
239
+ );
240
+
241
+ const [columnNamesKeys, keysToColumnNames] = getColumnHelpers(columns);
242
+
243
+ return (
244
+ <>
245
+ {shouldValidateStep1 && !repoSetsSelectionIsValid && (
246
+ <Alert
247
+ ouiaId="no-reposet-changes-alert"
248
+ variant="info"
249
+ isInline
250
+ title={__('Change the status of at least one repository.')}
251
+ style={{ marginBottom: '1rem' }}
252
+ />
253
+ )}
254
+ <TableIndexPage
255
+ customToolbarItems={[actionButton]}
256
+ selectionToolbar={selectionToolbar}
257
+ results={repoSetsResults}
258
+ metadata={repoSetsMetadata}
259
+ response={repoSetsResponse}
260
+ tableType="repository_sets"
261
+ apiUrl={repoSetsUrlForOrg(orgId)}
262
+ apiOptions={apiOptions}
263
+ selectedCount={selectedCount}
264
+ selectPage={selectPage}
265
+ selectNone={selectNone}
266
+ customSearchProps={{
267
+ autocomplete: {
268
+ url: katelloApi.getApiUrl('/repository_sets/auto_complete_search'),
269
+ },
270
+ }}
271
+ bulkSelect={repoSetsBulkSelect}
272
+ updateParamsByUrl={false}
273
+ >
274
+ <Table
275
+ childrenOutsideTbody
276
+ showCheckboxes
277
+ rowSelectTd={RowSelectTd}
278
+ selectOne={selectOne}
279
+ isSelected={isSelected}
280
+ isEmbedded
281
+ idColumn="label"
282
+ columns={columns}
283
+ refreshData={noop}
284
+ url=""
285
+ results={repoSetsResults}
286
+ isPending={repoSetsLoadingStatus === STATUS.PENDING}
287
+ params={{ ...repoSetsMetadata, perPage, page }}
288
+ setParams={setRepoSetsParamsAndAPI}
289
+ page={page}
290
+ perPage={perPage}
291
+ itemCount={subtotal}
292
+ >
293
+ {repoSetsResults.map((result, rowIndex) => {
294
+ const repoLabel = result.label;
295
+ const isExpanded = repoIsExpanded(repoLabel);
296
+ return (
297
+ <Tbody isExpanded={isExpanded} key={`tbody1-${repoLabel}`}>
298
+ <Tr
299
+ key={repoLabel}
300
+ ouiaId={`table-row-${rowIndex}`}
301
+ isClickable
302
+ >
303
+ <Td
304
+ expand={{
305
+ rowIndex,
306
+ isExpanded,
307
+ onToggle: (_event, _rInx, isOpen) =>
308
+ expandedRepos.onToggle(isOpen, repoLabel),
309
+ }}
310
+ />
311
+ <RowSelectTd
312
+ rowData={result}
313
+ selectOne={selectOne}
314
+ isSelected={isSelected}
315
+ idColumnName="label"
316
+ />
317
+ {columnNamesKeys.map(k => (
318
+ <Td key={k} dataLabel={keysToColumnNames[k]}>
319
+ {columns[k].wrapper
320
+ ? columns[k].wrapper(result)
321
+ : result[k]}
322
+ </Td>
323
+ ))}
324
+ </Tr>
325
+ <Tr key={`child-row-${repoLabel}`} ouiaId={`child-row-${repoLabel}`} isExpanded={isExpanded}>
326
+ <Td />
327
+ <Td />
328
+ <Td colSpan={2}>
329
+ <pre style={{ marginTop: '0.63rem' }} id={`pre-repo-label-${repoLabel}`}>{repoLabel}</pre>
330
+ </Td>
331
+ </Tr>
332
+ </Tbody>
333
+ );
334
+ })}
335
+ </Table>
336
+ </TableIndexPage>
337
+ </>
338
+ );
339
+ };
340
+
341
+ BulkRepositorySetsTable.propTypes = {
342
+ repoSetsBulkSelect: PropTypes.shape({
343
+ selectAll: PropTypes.func.isRequired,
344
+ selectPage: PropTypes.func.isRequired,
345
+ selectNone: PropTypes.func.isRequired,
346
+ selectOne: PropTypes.func.isRequired,
347
+ isSelected: PropTypes.func.isRequired,
348
+ selectedCount: PropTypes.number.isRequired,
349
+ areAllRowsSelected: PropTypes.func.isRequired,
350
+ areAllRowsOnPageSelected: PropTypes.func.isRequired,
351
+ updateSearchQuery: PropTypes.func.isRequired,
352
+ selectedResults: PropTypes.arrayOf(PropTypes.shape({})).isRequired,
353
+ }).isRequired,
354
+ repoSetsResults: PropTypes.arrayOf(PropTypes.shape({})),
355
+ repoSetsMetadata: PropTypes.shape({
356
+ total: PropTypes.number,
357
+ page: PropTypes.number,
358
+ subtotal: PropTypes.number,
359
+ per_page: PropTypes.number,
360
+ }).isRequired,
361
+ repoSetsResponse: PropTypes.shape({
362
+ response: PropTypes.shape({}),
363
+ status: PropTypes.string,
364
+ }).isRequired,
365
+ };
366
+
367
+ BulkRepositorySetsTable.defaultProps = {
368
+ repoSetsResults: [],
369
+ };
370
+
371
+ export default BulkRepositorySetsTable;
@@ -0,0 +1,79 @@
1
+ import React, { useContext } from 'react';
2
+ import {
3
+ Badge,
4
+ Button,
5
+ Flex,
6
+ FlexItem,
7
+ Text,
8
+ TextContent,
9
+ TextVariants,
10
+ Grid,
11
+ GridItem,
12
+ useWizardContext,
13
+ } from '@patternfly/react-core';
14
+ import { translate as __ } from 'foremanReact/common/I18n';
15
+ import { BulkRepositorySetsWizardContext } from './BulkRepositorySetsWizard';
16
+ import { dropdownValues } from './01_BulkRepositorySetsTable';
17
+
18
+ export const BulkRepositorySetsReview = () => {
19
+ const { goToStepById } = useWizardContext();
20
+ const {
21
+ pendingOverrides,
22
+ } = useContext(BulkRepositorySetsWizardContext);
23
+ const overridesEntries = Object.entries(pendingOverrides);
24
+ const overridesTexts = overridesEntries
25
+ .filter(([_repoLabel, value]) => Number(value) !== 0)
26
+ .map(([repoLabel, value]) => [repoLabel, dropdownValues[value]]);
27
+
28
+ return (
29
+ <>
30
+ <TextContent>
31
+ <Text component={TextVariants.h3} ouiaId="bulk-repo-sets-wizard-review-header">
32
+ {__('Review')}
33
+ </Text>
34
+ <Text component={TextVariants.p} ouiaId="bulk-repo-sets-wizard-review-description">
35
+ {__('Review and then click \'Set content overrides.\' Status will be changed for the selected repository sets on the selected hosts.')}
36
+ </Text>
37
+ </TextContent>
38
+ <Grid>
39
+ <GridItem span={8}>
40
+ <Flex>
41
+ <FlexItem>
42
+ <Text component={TextVariants.h4} ouiaId="bulk-repo-sets-wizard-review-header">
43
+ <strong>{__('Changed status')}</strong>
44
+ </Text>
45
+ </FlexItem>
46
+ <FlexItem>
47
+ <Badge isRead>
48
+ {overridesTexts.length}
49
+ </Badge>
50
+ </FlexItem>
51
+ </Flex>
52
+ </GridItem>
53
+ <GridItem span={4}>
54
+ <Text component={TextVariants.p} ouiaId="brsw-review-step-edit-wrapper">
55
+ <Button variant="link" onClick={() => goToStepById('brsw-step-1')} ouiaId="brsw-review-step-edit-btn">
56
+ {__('Edit')}
57
+ </Button>
58
+ </Text>
59
+ </GridItem>
60
+ {overridesTexts.map(([repoLabel, actionText]) => (
61
+ <React.Fragment key={repoLabel}>
62
+ <GridItem span={8}>
63
+ <Text component={TextVariants.p} ouiaId="brsw-review-step-repo-label">
64
+ {repoLabel}
65
+ </Text>
66
+ </GridItem>
67
+ <GridItem span={4}>
68
+ <Text component={TextVariants.p} ouiaId="brsw-review-step-action-text">
69
+ {actionText}
70
+ </Text>
71
+ </GridItem>
72
+ </React.Fragment>
73
+ ))}
74
+ </Grid>
75
+ </>
76
+ );
77
+ };
78
+
79
+ export default BulkRepositorySetsReview;
@@ -0,0 +1,73 @@
1
+ import React, { useContext } from 'react';
2
+ import { useDispatch } from 'react-redux';
3
+ import { translate as __ } from 'foremanReact/common/I18n';
4
+ import {
5
+ Button,
6
+ WizardFooterWrapper,
7
+ useWizardContext,
8
+ } from '@patternfly/react-core';
9
+ import { BulkRepositorySetsWizardContext } from './BulkRepositorySetsWizard';
10
+ import { bulkUpdateHostContentOverrides } from './actions';
11
+ import { pendingOverrideToApiParamItem } from './helpers';
12
+
13
+ export const BulkRepositorySetsReviewFooter = () => {
14
+ const {
15
+ pendingOverrides,
16
+ finishButtonText,
17
+ allStepsValid,
18
+ finishButtonLoading,
19
+ setFinishButtonLoading,
20
+ closeModal,
21
+ hostsBulkSelect,
22
+ } = useContext(BulkRepositorySetsWizardContext);
23
+
24
+ const { goToStepById } = useWizardContext();
25
+ const dispatch = useDispatch();
26
+
27
+ const overridesEntries = Object.entries(pendingOverrides);
28
+ const apiParams = overridesEntries
29
+ .map(([repoLabel, value]) => pendingOverrideToApiParamItem({ repoLabel, value }))
30
+ .filter(item => item);
31
+
32
+ const saveContentOverrides = () => {
33
+ const requestBody = {
34
+ included: {
35
+ search: hostsBulkSelect.fetchBulkParams(),
36
+ },
37
+ content_overrides: apiParams,
38
+ };
39
+ dispatch(bulkUpdateHostContentOverrides(
40
+ requestBody,
41
+ closeModal, closeModal,
42
+ ));
43
+ };
44
+
45
+ const handleFinishButtonClick = () => {
46
+ setFinishButtonLoading(true);
47
+ saveContentOverrides();
48
+ closeModal();
49
+ };
50
+ return (
51
+ <WizardFooterWrapper>
52
+ <Button variant="secondary" onClick={() => goToStepById('brsw-step-2')} isDisabled={finishButtonLoading} ouiaId="bulk-reposets-wiz-step3-back">
53
+ {__('Back')}
54
+ </Button>
55
+ <Button
56
+ key="bulk-repo-sets-wizard-finish-button"
57
+ ouiaId="bulk-repo-sets-wizard-finish-button"
58
+ type="submit"
59
+ variant="primary"
60
+ isLoading={finishButtonLoading}
61
+ isDisabled={finishButtonLoading || !allStepsValid}
62
+ onClick={handleFinishButtonClick}
63
+ >
64
+ {finishButtonText}
65
+ </Button>
66
+ <Button variant="link" onClick={closeModal} isDisabled={finishButtonLoading} ouiaId="bulk-repo-sets-wiz-step3-cancel">
67
+ {__('Cancel')}
68
+ </Button>
69
+ </WizardFooterWrapper>
70
+ );
71
+ };
72
+
73
+ export default BulkRepositorySetsReviewFooter;
@@ -0,0 +1,170 @@
1
+ import React, { useState, createContext, useContext } from 'react';
2
+ import {
3
+ Text,
4
+ TextVariants,
5
+ TextContent,
6
+ Wizard,
7
+ WizardHeader,
8
+ WizardStep,
9
+ } from '@patternfly/react-core';
10
+
11
+ import { translate as __ } from 'foremanReact/common/I18n';
12
+ import { useForemanModal } from 'foremanReact/components/ForemanModal/ForemanModalHooks';
13
+ import { useBulkSelect } from 'foremanReact/components/PF4/TableIndexPage/Table/TableHooks';
14
+ import { useForemanOrganization } from 'foremanReact/Root/Context/ForemanContext';
15
+ import { ForemanActionsBarContext } from 'foremanReact/components/HostDetails/ActionsBar';
16
+ import { useTableIndexAPIResponse, useSetParamsAndApiAndSearch } from 'foremanReact/components/PF4/TableIndexPage/Table/TableIndexHooks';
17
+
18
+ import { BulkRepositorySetsTable } from './01_BulkRepositorySetsTable';
19
+ import { BulkRepositorySetsReview } from './03_Review';
20
+ import HostReview from '../HostReview';
21
+ import katelloApi from '../../../../../services/api';
22
+ import { useHostsBulkSelect } from '../BulkPackagesWizard/BulkPackagesWizard';
23
+ import { BulkRepositorySetsReviewFooter } from './03_ReviewFooter';
24
+
25
+ const DEFAULT_PER_PAGE = 5;
26
+ export const BulkRepositorySetsWizardContext = createContext({});
27
+ export const repoSetsUrlForOrg = orgId =>
28
+ katelloApi.getApiUrl(`/repository_sets?per_page=${DEFAULT_PER_PAGE}&include_permissions=true&enabled=true&with_custom=true&organization_id=${orgId}`);
29
+
30
+ const BulkRepositorySetsWizard = () => {
31
+ const { modalOpen, setModalClosed: closeModal } = useForemanModal({ id: 'bulk-repo-sets-wizard' });
32
+ const orgId = useForemanOrganization()?.id;
33
+ const [pendingOverrides, setPendingOverrides] = useState({}); // { repo_label: 1 }
34
+ const [shouldValidateStep2, setShouldValidateStep2] = useState(false);
35
+ const [shouldValidateStep1, setShouldValidateStep1] = useState(false);
36
+ const [, setCurrentStep] = useState();
37
+ const onStepChange = (_event, newStep) => setCurrentStep((oldStep) => {
38
+ setShouldValidateStep1(true);
39
+ if (oldStep === 'brsw-step-2') setShouldValidateStep2(true);
40
+ return newStep?.id;
41
+ });
42
+ const apiOptions = { key: 'BULK_HOST_REPO_SETS' };
43
+
44
+ const finishButtonText = __('Set content overrides');
45
+ const replacementResponse = !modalOpen ? { response: {} } : false;
46
+ const { selectedCount: initialSelectedHostCount, fetchBulkParams }
47
+ = useContext(ForemanActionsBarContext);
48
+ const repoSetsResponse = useTableIndexAPIResponse({
49
+ replacementResponse, // don't fetch data if modal is closed
50
+ apiUrl: repoSetsUrlForOrg(orgId),
51
+ apiOptions,
52
+ defaultParams: { per_page: DEFAULT_PER_PAGE },
53
+ });
54
+
55
+ const {
56
+ response: {
57
+ results: repoSetsResults,
58
+ ...repoSetsMetadata
59
+ },
60
+ setAPIOptions,
61
+ } = repoSetsResponse;
62
+
63
+ const { total, page, subtotal } = repoSetsMetadata;
64
+
65
+ const repoSetsBulkSelect = useBulkSelect({
66
+ results: repoSetsResults,
67
+ metadata: { total, page, selectable: subtotal },
68
+ idColumn: 'label',
69
+ });
70
+
71
+ const {
72
+ setParamsAndAPI: setRepoSetsParamsAndAPI,
73
+ } = useSetParamsAndApiAndSearch({
74
+ defaultParams: { search: '' },
75
+ apiOptions,
76
+ setAPIOptions,
77
+ updateSearchQuery: repoSetsBulkSelect.updateSearchQuery,
78
+ pushToHistory: false,
79
+ });
80
+
81
+ const initialSelectedHosts = fetchBulkParams();
82
+
83
+ const hostsBulkSelect =
84
+ useHostsBulkSelect({ initialSelectedHosts, modalIsOpen: modalOpen });
85
+
86
+ // eslint-disable-next-line no-restricted-globals
87
+ const selectionIsValid = count => count > 0 || isNaN(count);
88
+ const pendingOverridesCount =
89
+ Object.values(pendingOverrides).filter(val => Number(val) !== 0).length;
90
+ const repoSetsSelectionIsValid =
91
+ selectionIsValid(pendingOverridesCount);
92
+ const hostSelectionIsValid = selectionIsValid(hostsBulkSelect.hostsBulkSelect.selectedCount);
93
+ const step1Valid = shouldValidateStep1 ? repoSetsSelectionIsValid : true;
94
+ const step2Valid = shouldValidateStep2 ? hostSelectionIsValid : true;
95
+ const allStepsValid = step1Valid && step2Valid;
96
+ const [finishButtonLoading, setFinishButtonLoading] = useState(false);
97
+
98
+ const BulkRepositorySetsWizardContextData = {
99
+ pendingOverrides,
100
+ setPendingOverrides,
101
+ finishButtonText,
102
+ initialSelectedHostCount,
103
+ shouldValidateStep1,
104
+ setShouldValidateStep1,
105
+ setShouldValidateStep2,
106
+ allStepsValid,
107
+ repoSetsSelectionIsValid,
108
+ setRepoSetsParamsAndAPI,
109
+ finishButtonLoading,
110
+ setFinishButtonLoading,
111
+ closeModal,
112
+ repoSetsBulkSelect,
113
+ repoSetsResults,
114
+ repoSetsMetadata,
115
+ repoSetsResponse,
116
+ hostsBulkSelect: hostsBulkSelect.hostsBulkSelect,
117
+ };
118
+ return (
119
+ <BulkRepositorySetsWizardContext.Provider value={BulkRepositorySetsWizardContextData}>
120
+ <Wizard
121
+ header={<WizardHeader title={__('Manage repository sets')} onClose={closeModal} />}
122
+ onStepChange={onStepChange}
123
+ >
124
+ <WizardStep
125
+ name={__('Select repository sets')}
126
+ id="brsw-step-1"
127
+ footer={{ isNextDisabled: !step1Valid, onClose: closeModal }}
128
+ status={step1Valid ? 'default' : 'error'}
129
+ >
130
+ <TextContent>
131
+ <Text component={TextVariants.h3} ouiaId="bulk-repo-sets-wizard-header">
132
+ {__('Select repository sets')}
133
+ </Text>
134
+ <Text component={TextVariants.p} ouiaId="bulk-repo-sets-wizard-description">
135
+ {__('Below you can add content overrides, which change whether a repository is enabled or disabled. Change their state one by one, or use the checkboxes and select an action to perform.')}
136
+ </Text>
137
+ </TextContent>
138
+ <BulkRepositorySetsTable
139
+ repoSetsBulkSelect={repoSetsBulkSelect}
140
+ repoSetsResults={repoSetsResults}
141
+ repoSetsMetadata={repoSetsMetadata}
142
+ repoSetsResponse={repoSetsResponse}
143
+ />
144
+ </WizardStep>
145
+ <WizardStep
146
+ name={__('Review hosts')}
147
+ id="brsw-step-2"
148
+ footer={{ isNextDisabled: !step2Valid, onClose: closeModal }}
149
+ status={step2Valid ? 'default' : 'error'}
150
+ >
151
+ <HostReview
152
+ key={modalOpen}
153
+ hostsBulkSelect={hostsBulkSelect}
154
+ initialSelectedHosts={initialSelectedHosts}
155
+ setShouldValidateStep={setShouldValidateStep2}
156
+ />
157
+ </WizardStep>
158
+ <WizardStep
159
+ name={__('Review')}
160
+ id="brsw-step-3"
161
+ footer={<BulkRepositorySetsReviewFooter />}
162
+ >
163
+ <BulkRepositorySetsReview />
164
+ </WizardStep>
165
+ </Wizard>
166
+ </BulkRepositorySetsWizardContext.Provider>
167
+ );
168
+ };
169
+
170
+ export default BulkRepositorySetsWizard;