katello 4.18.1 → 4.19.0.rc2

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 (388) hide show
  1. checksums.yaml +4 -4
  2. data/app/assets/javascripts/katello/locale/bn/katello.js +379 -109
  3. data/app/assets/javascripts/katello/locale/bn_IN/katello.js +379 -109
  4. data/app/assets/javascripts/katello/locale/ca/katello.js +379 -109
  5. data/app/assets/javascripts/katello/locale/cs/katello.js +380 -110
  6. data/app/assets/javascripts/katello/locale/cs_CZ/katello.js +382 -112
  7. data/app/assets/javascripts/katello/locale/de/katello.js +385 -115
  8. data/app/assets/javascripts/katello/locale/de_AT/katello.js +379 -109
  9. data/app/assets/javascripts/katello/locale/de_DE/katello.js +379 -109
  10. data/app/assets/javascripts/katello/locale/el/katello.js +380 -110
  11. data/app/assets/javascripts/katello/locale/en/katello.js +380 -110
  12. data/app/assets/javascripts/katello/locale/en_GB/katello.js +379 -109
  13. data/app/assets/javascripts/katello/locale/en_US/katello.js +379 -109
  14. data/app/assets/javascripts/katello/locale/es/katello.js +383 -113
  15. data/app/assets/javascripts/katello/locale/et_EE/katello.js +379 -109
  16. data/app/assets/javascripts/katello/locale/fr/katello.js +388 -118
  17. data/app/assets/javascripts/katello/locale/gl/katello.js +379 -109
  18. data/app/assets/javascripts/katello/locale/gu/katello.js +379 -109
  19. data/app/assets/javascripts/katello/locale/he_IL/katello.js +379 -109
  20. data/app/assets/javascripts/katello/locale/hi/katello.js +379 -109
  21. data/app/assets/javascripts/katello/locale/id/katello.js +379 -109
  22. data/app/assets/javascripts/katello/locale/it/katello.js +379 -109
  23. data/app/assets/javascripts/katello/locale/ja/katello.js +388 -118
  24. data/app/assets/javascripts/katello/locale/ka/katello.js +385 -115
  25. data/app/assets/javascripts/katello/locale/kn/katello.js +379 -109
  26. data/app/assets/javascripts/katello/locale/ko/katello.js +388 -118
  27. data/app/assets/javascripts/katello/locale/ml_IN/katello.js +379 -109
  28. data/app/assets/javascripts/katello/locale/mr/katello.js +379 -109
  29. data/app/assets/javascripts/katello/locale/nl_NL/katello.js +379 -109
  30. data/app/assets/javascripts/katello/locale/or/katello.js +379 -109
  31. data/app/assets/javascripts/katello/locale/pa/katello.js +379 -109
  32. data/app/assets/javascripts/katello/locale/pl/katello.js +379 -109
  33. data/app/assets/javascripts/katello/locale/pl_PL/katello.js +379 -109
  34. data/app/assets/javascripts/katello/locale/pt/katello.js +379 -109
  35. data/app/assets/javascripts/katello/locale/pt_BR/katello.js +383 -113
  36. data/app/assets/javascripts/katello/locale/ro/katello.js +379 -109
  37. data/app/assets/javascripts/katello/locale/ro_RO/katello.js +379 -109
  38. data/app/assets/javascripts/katello/locale/ru/katello.js +381 -111
  39. data/app/assets/javascripts/katello/locale/sl/katello.js +379 -109
  40. data/app/assets/javascripts/katello/locale/sv_SE/katello.js +379 -109
  41. data/app/assets/javascripts/katello/locale/ta/katello.js +379 -109
  42. data/app/assets/javascripts/katello/locale/ta_IN/katello.js +379 -109
  43. data/app/assets/javascripts/katello/locale/te/katello.js +379 -109
  44. data/app/assets/javascripts/katello/locale/tr/katello.js +379 -109
  45. data/app/assets/javascripts/katello/locale/vi/katello.js +379 -109
  46. data/app/assets/javascripts/katello/locale/vi_VN/katello.js +379 -109
  47. data/app/assets/javascripts/katello/locale/zh/katello.js +379 -109
  48. data/app/assets/javascripts/katello/locale/zh_CN/katello.js +388 -118
  49. data/app/assets/javascripts/katello/locale/zh_TW/katello.js +381 -111
  50. data/app/controllers/katello/api/registry/registry_proxies_controller.rb +41 -12
  51. data/app/controllers/katello/api/rhsm/candlepin_proxies_controller.rb +1 -1
  52. data/app/controllers/katello/api/v2/activation_keys_controller.rb +3 -65
  53. data/app/controllers/katello/api/v2/content_view_filter_rules_controller.rb +1 -1
  54. data/app/controllers/katello/api/v2/content_views_controller.rb +18 -3
  55. data/app/controllers/katello/api/v2/debs_controller.rb +21 -11
  56. data/app/controllers/katello/api/v2/docker_tags_controller.rb +7 -0
  57. data/app/controllers/katello/api/v2/flatpak_remote_repositories_controller.rb +21 -19
  58. data/app/controllers/katello/api/v2/host_debs_controller.rb +16 -1
  59. data/app/controllers/katello/api/v2/host_subscriptions_controller.rb +3 -60
  60. data/app/controllers/katello/api/v2/hosts_bulk_actions_controller.rb +10 -53
  61. data/app/controllers/katello/api/v2/repositories_controller.rb +0 -1
  62. data/app/controllers/katello/concerns/api/v2/hosts_controller_extensions.rb +10 -0
  63. data/app/controllers/katello/concerns/organizations_controller_extensions.rb +3 -0
  64. data/app/lib/actions/candlepin/activation_key/create.rb +0 -2
  65. data/app/lib/actions/candlepin/activation_key/update.rb +0 -2
  66. data/app/lib/actions/candlepin/product/content_create.rb +3 -5
  67. data/app/lib/actions/candlepin/product/content_update.rb +2 -3
  68. data/app/lib/actions/helpers/rolling_cv_repos.rb +1 -1
  69. data/app/lib/actions/katello/activation_key/create.rb +0 -1
  70. data/app/lib/actions/katello/activation_key/update.rb +0 -2
  71. data/app/lib/actions/katello/capsule_content/sync_capsule.rb +1 -6
  72. data/app/lib/actions/katello/content_credential/update.rb +1 -1
  73. data/app/lib/actions/katello/content_view/add_rolling_repo_clone.rb +18 -24
  74. data/app/lib/actions/katello/content_view/create.rb +9 -4
  75. data/app/lib/actions/katello/content_view/refresh_rolling_repo.rb +6 -1
  76. data/app/lib/actions/katello/content_view/remove_rolling_repo_clone.rb +16 -11
  77. data/app/lib/actions/katello/content_view/update.rb +34 -7
  78. data/app/lib/actions/katello/product/content_create.rb +2 -2
  79. data/app/lib/actions/katello/product/content_destroy.rb +1 -1
  80. data/app/lib/actions/katello/repository/check_matching_content.rb +1 -1
  81. data/app/lib/actions/katello/repository/clone_contents.rb +1 -1
  82. data/app/lib/actions/katello/repository/create.rb +1 -1
  83. data/app/lib/actions/katello/repository/destroy.rb +4 -4
  84. data/app/lib/actions/katello/repository/finish_upload.rb +1 -1
  85. data/app/lib/actions/katello/repository/sync.rb +1 -1
  86. data/app/lib/actions/pulp3/orchestration/repository/copy_all_units.rb +2 -2
  87. data/app/lib/actions/pulp3/orchestration/repository/generate_metadata.rb +1 -1
  88. data/app/lib/actions/pulp3/orchestration/repository/multi_copy_all_units.rb +1 -1
  89. data/app/lib/actions/pulp3/repository/save_publication.rb +3 -1
  90. data/app/lib/actions/pulp3/repository/save_version.rb +45 -24
  91. data/app/lib/actions/pulp3/repository/save_versions.rb +2 -1
  92. data/app/lib/katello/resources/candlepin/activation_key.rb +3 -4
  93. data/app/lib/katello/resources/candlepin/upstream_job.rb +9 -1
  94. data/app/lib/katello/resources/candlepin.rb +4 -0
  95. data/app/models/katello/authorization/repository.rb +17 -4
  96. data/app/models/katello/concerns/subscription_facet_host_extensions.rb +0 -7
  97. data/app/models/katello/content_view_deb_filter.rb +10 -0
  98. data/app/models/katello/content_view_deb_filter_rule.rb +7 -0
  99. data/app/models/katello/deb.rb +10 -10
  100. data/app/models/katello/erratum.rb +1 -1
  101. data/app/models/katello/glue/provider.rb +14 -3
  102. data/app/models/katello/host/content_facet.rb +1 -1
  103. data/app/models/katello/host/subscription_facet.rb +1 -7
  104. data/app/models/katello/product_content.rb +2 -2
  105. data/app/models/katello/repository.rb +4 -23
  106. data/app/models/katello/root_repository.rb +2 -5
  107. data/app/services/katello/candlepin/event_handler.rb +0 -33
  108. data/app/services/katello/candlepin/message_handler.rb +0 -41
  109. data/app/services/katello/content_unit_indexer.rb +59 -13
  110. data/app/services/katello/product_content_finder.rb +5 -4
  111. data/app/services/katello/pulp3/alternate_content_source.rb +2 -2
  112. data/app/services/katello/pulp3/ansible_collection.rb +1 -0
  113. data/app/services/katello/pulp3/api/content_guard.rb +5 -5
  114. data/app/services/katello/pulp3/api/core.rb +10 -0
  115. data/app/services/katello/pulp3/deb.rb +1 -0
  116. data/app/services/katello/pulp3/docker_manifest.rb +1 -0
  117. data/app/services/katello/pulp3/docker_manifest_list.rb +1 -0
  118. data/app/services/katello/pulp3/docker_tag.rb +1 -0
  119. data/app/services/katello/pulp3/file_unit.rb +1 -0
  120. data/app/services/katello/pulp3/generic_content_unit.rb +1 -0
  121. data/app/services/katello/pulp3/module_stream.rb +1 -0
  122. data/app/services/katello/pulp3/package_group.rb +1 -0
  123. data/app/services/katello/pulp3/repository/apt.rb +41 -16
  124. data/app/services/katello/pulp3/repository.rb +59 -10
  125. data/app/services/katello/pulp3/rpm.rb +3 -2
  126. data/app/services/katello/pulp3/srpm.rb +3 -2
  127. data/app/services/katello/pulp3/task_group.rb +1 -1
  128. data/app/services/katello/registration_manager.rb +19 -17
  129. data/app/services/katello/repository_type_manager.rb +7 -5
  130. data/app/services/katello/smart_proxy_helper.rb +1 -6
  131. data/app/views/foreman/job_templates/upload_profile.erb +5 -0
  132. data/app/views/katello/api/v2/activation_keys/base.json.rabl +1 -1
  133. data/app/views/katello/api/v2/content_views/base.json.rabl +1 -0
  134. data/app/views/katello/api/v2/debs/thindex.json.rabl +6 -0
  135. data/app/views/katello/api/v2/docker_tags/_base.json.rabl +32 -0
  136. data/app/views/katello/api/v2/docker_tags/show.json.rabl +0 -5
  137. data/app/views/katello/api/v2/flatpak_remotes/index.json.rabl +6 -0
  138. data/app/views/katello/api/v2/host_debs/installed_debs.json.rabl +6 -0
  139. data/app/views/katello/api/v2/hosts_bulk_actions/applicable_errata.json.rabl +1 -1
  140. data/app/views/katello/api/v2/hosts_bulk_actions/applicable_erratum.json.rabl +9 -0
  141. data/app/views/katello/api/v2/hosts_bulk_actions/installable_errata.json.rabl +1 -1
  142. data/app/views/katello/api/v2/hosts_bulk_actions/{erratum.json.rabl → installable_erratum.json.rabl} +3 -3
  143. data/app/views/katello/api/v2/subscription_facet/base.json.rabl +1 -1
  144. data/config/initializers/monkeys.rb +1 -0
  145. data/config/routes/api/v2.rb +2 -2
  146. data/config/routes/overrides.rb +2 -7
  147. data/config/routes.rb +2 -0
  148. data/db/migrate/20211019192121_create_cdn_configuration.katello.rb +1 -1
  149. data/db/migrate/20250912000000_add_pulp_prn_fields.rb +73 -0
  150. data/db/migrate/20250912000001_populate_pulp_prn_fields.rb +403 -0
  151. data/db/migrate/20251009142516_remove_auto_attach_from_activation_keys.rb +5 -0
  152. data/db/migrate/20251009142517_remove_autoheal_from_subscription_facets.rb +5 -0
  153. data/db/seeds.d/111-upgrade_tasks.rb +2 -0
  154. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/i18n/locale/bn.po +10 -0
  155. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/i18n/locale/bn_IN.po +10 -0
  156. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/i18n/locale/ca.po +10 -0
  157. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/i18n/locale/cs_CZ.po +10 -0
  158. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/i18n/locale/de.po +10 -0
  159. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/i18n/locale/de_AT.po +10 -0
  160. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/i18n/locale/de_DE.po +10 -0
  161. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/i18n/locale/el.po +12 -2
  162. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/i18n/locale/en_GB.po +10 -0
  163. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/i18n/locale/en_US.po +10 -0
  164. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/i18n/locale/es.po +10 -0
  165. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/i18n/locale/et_EE.po +10 -0
  166. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/i18n/locale/fr.po +10 -0
  167. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/i18n/locale/gl.po +10 -0
  168. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/i18n/locale/gu.po +10 -0
  169. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/i18n/locale/he_IL.po +10 -0
  170. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/i18n/locale/hi.po +10 -0
  171. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/i18n/locale/id.po +10 -0
  172. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/i18n/locale/it.po +10 -0
  173. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/i18n/locale/ja.po +10 -0
  174. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/i18n/locale/ka.po +10 -0
  175. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/i18n/locale/kn.po +10 -0
  176. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/i18n/locale/ko.po +10 -0
  177. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/i18n/locale/ml_IN.po +10 -0
  178. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/i18n/locale/mr.po +10 -0
  179. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/i18n/locale/nl_NL.po +10 -0
  180. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/i18n/locale/or.po +10 -0
  181. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/i18n/locale/pa.po +10 -0
  182. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/i18n/locale/pl.po +10 -0
  183. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/i18n/locale/pl_PL.po +10 -0
  184. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/i18n/locale/pt.po +10 -0
  185. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/i18n/locale/pt_BR.po +10 -0
  186. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/i18n/locale/ro.po +10 -0
  187. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/i18n/locale/ro_RO.po +10 -0
  188. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/i18n/locale/ru.po +10 -0
  189. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/i18n/locale/sl.po +10 -0
  190. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/i18n/locale/sv_SE.po +10 -0
  191. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/i18n/locale/ta.po +10 -0
  192. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/i18n/locale/ta_IN.po +10 -0
  193. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/i18n/locale/te.po +10 -0
  194. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/i18n/locale/tr.po +10 -0
  195. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/i18n/locale/vi.po +10 -0
  196. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/i18n/locale/vi_VN.po +10 -0
  197. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/i18n/locale/zh.po +10 -0
  198. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/i18n/locale/zh_CN.po +10 -0
  199. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/i18n/locale/zh_TW.po +10 -0
  200. data/lib/katello/permission_creator.rb +2 -2
  201. data/lib/katello/permissions/host_permissions.rb +0 -6
  202. data/lib/katello/plugin.rb +17 -8
  203. data/lib/katello/tasks/jenkins.rake +1 -1
  204. data/lib/katello/tasks/upgrades/4.19/enable_structured_apt_for_deb.rake +87 -0
  205. data/lib/katello/tasks/upgrades/4.19/populate_repository_version_prns.rake +32 -0
  206. data/lib/katello/version.rb +1 -1
  207. data/lib/monkeys/fix_rpm_repository_gpgcheck.rb +38 -0
  208. data/locale/action_names.rb +0 -6
  209. data/locale/bn/LC_MESSAGES/katello.mo +0 -0
  210. data/locale/bn/katello.po +379 -109
  211. data/locale/bn_IN/LC_MESSAGES/katello.mo +0 -0
  212. data/locale/bn_IN/katello.po +379 -109
  213. data/locale/ca/LC_MESSAGES/katello.mo +0 -0
  214. data/locale/ca/katello.po +379 -109
  215. data/locale/cs/LC_MESSAGES/katello.mo +0 -0
  216. data/locale/cs/katello.po +380 -111
  217. data/locale/cs_CZ/LC_MESSAGES/katello.mo +0 -0
  218. data/locale/cs_CZ/katello.po +382 -112
  219. data/locale/de/LC_MESSAGES/katello.mo +0 -0
  220. data/locale/de/katello.po +386 -116
  221. data/locale/de_AT/LC_MESSAGES/katello.mo +0 -0
  222. data/locale/de_AT/katello.po +379 -109
  223. data/locale/de_DE/LC_MESSAGES/katello.mo +0 -0
  224. data/locale/de_DE/katello.po +379 -109
  225. data/locale/el/LC_MESSAGES/katello.mo +0 -0
  226. data/locale/el/katello.po +381 -111
  227. data/locale/en/LC_MESSAGES/katello.mo +0 -0
  228. data/locale/en/katello.po +380 -111
  229. data/locale/en_GB/LC_MESSAGES/katello.mo +0 -0
  230. data/locale/en_GB/katello.po +379 -109
  231. data/locale/en_US/LC_MESSAGES/katello.mo +0 -0
  232. data/locale/en_US/katello.po +379 -109
  233. data/locale/es/LC_MESSAGES/katello.mo +0 -0
  234. data/locale/es/katello.po +383 -113
  235. data/locale/et_EE/LC_MESSAGES/katello.mo +0 -0
  236. data/locale/et_EE/katello.po +379 -109
  237. data/locale/fr/LC_MESSAGES/katello.mo +0 -0
  238. data/locale/fr/katello.po +389 -119
  239. data/locale/gl/LC_MESSAGES/katello.mo +0 -0
  240. data/locale/gl/katello.po +379 -109
  241. data/locale/gu/LC_MESSAGES/katello.mo +0 -0
  242. data/locale/gu/katello.po +379 -109
  243. data/locale/he_IL/LC_MESSAGES/katello.mo +0 -0
  244. data/locale/he_IL/katello.po +379 -109
  245. data/locale/hi/LC_MESSAGES/katello.mo +0 -0
  246. data/locale/hi/katello.po +379 -109
  247. data/locale/id/LC_MESSAGES/katello.mo +0 -0
  248. data/locale/id/katello.po +379 -109
  249. data/locale/it/LC_MESSAGES/katello.mo +0 -0
  250. data/locale/it/katello.po +379 -109
  251. data/locale/ja/LC_MESSAGES/katello.mo +0 -0
  252. data/locale/ja/katello.po +390 -119
  253. data/locale/ka/LC_MESSAGES/katello.mo +0 -0
  254. data/locale/ka/katello.po +385 -115
  255. data/locale/katello.pot +1273 -831
  256. data/locale/kn/LC_MESSAGES/katello.mo +0 -0
  257. data/locale/kn/katello.po +379 -109
  258. data/locale/ko/LC_MESSAGES/katello.mo +0 -0
  259. data/locale/ko/katello.po +389 -119
  260. data/locale/ml_IN/LC_MESSAGES/katello.mo +0 -0
  261. data/locale/ml_IN/katello.po +379 -109
  262. data/locale/mr/LC_MESSAGES/katello.mo +0 -0
  263. data/locale/mr/katello.po +379 -109
  264. data/locale/nl_NL/LC_MESSAGES/katello.mo +0 -0
  265. data/locale/nl_NL/katello.po +379 -109
  266. data/locale/or/LC_MESSAGES/katello.mo +0 -0
  267. data/locale/or/katello.po +379 -109
  268. data/locale/pa/LC_MESSAGES/katello.mo +0 -0
  269. data/locale/pa/katello.po +379 -109
  270. data/locale/pl/LC_MESSAGES/katello.mo +0 -0
  271. data/locale/pl/katello.po +379 -109
  272. data/locale/pl_PL/LC_MESSAGES/katello.mo +0 -0
  273. data/locale/pl_PL/katello.po +379 -109
  274. data/locale/pt/LC_MESSAGES/katello.mo +0 -0
  275. data/locale/pt/katello.po +379 -109
  276. data/locale/pt_BR/LC_MESSAGES/katello.mo +0 -0
  277. data/locale/pt_BR/katello.po +383 -113
  278. data/locale/ro/LC_MESSAGES/katello.mo +0 -0
  279. data/locale/ro/katello.po +379 -109
  280. data/locale/ro_RO/LC_MESSAGES/katello.mo +0 -0
  281. data/locale/ro_RO/katello.po +379 -109
  282. data/locale/ru/LC_MESSAGES/katello.mo +0 -0
  283. data/locale/ru/katello.po +381 -111
  284. data/locale/sl/LC_MESSAGES/katello.mo +0 -0
  285. data/locale/sl/katello.po +379 -109
  286. data/locale/sv_SE/LC_MESSAGES/katello.mo +0 -0
  287. data/locale/sv_SE/katello.po +379 -109
  288. data/locale/ta/LC_MESSAGES/katello.mo +0 -0
  289. data/locale/ta/katello.po +379 -109
  290. data/locale/ta_IN/LC_MESSAGES/katello.mo +0 -0
  291. data/locale/ta_IN/katello.po +379 -109
  292. data/locale/te/LC_MESSAGES/katello.mo +0 -0
  293. data/locale/te/katello.po +379 -109
  294. data/locale/tr/LC_MESSAGES/katello.mo +0 -0
  295. data/locale/tr/katello.po +379 -109
  296. data/locale/vi/LC_MESSAGES/katello.mo +0 -0
  297. data/locale/vi/katello.po +379 -109
  298. data/locale/vi_VN/LC_MESSAGES/katello.mo +0 -0
  299. data/locale/vi_VN/katello.po +379 -109
  300. data/locale/zh/LC_MESSAGES/katello.mo +0 -0
  301. data/locale/zh/katello.po +379 -109
  302. data/locale/zh_CN/LC_MESSAGES/katello.mo +0 -0
  303. data/locale/zh_CN/katello.po +389 -119
  304. data/locale/zh_TW/LC_MESSAGES/katello.mo +0 -0
  305. data/locale/zh_TW/katello.po +381 -111
  306. data/webpack/ForemanColumnExtensions/index.js +46 -2
  307. data/webpack/components/Content/Details/__tests__/__snapshots__/ContentDetails.test.js.snap +2 -2
  308. data/webpack/components/extensions/HostDetails/Cards/SystemPurposeCard/SystemPurposeEditModal.js +0 -2
  309. data/webpack/components/extensions/HostDetails/Cards/SystemPurposeCard/__tests__/SystemPurposeEditModal.test.js +0 -2
  310. data/webpack/components/extensions/Hosts/ActionsBar/index.js +1 -0
  311. data/webpack/components/extensions/Hosts/BulkActions/BulkActionsConstants.js +7 -0
  312. data/webpack/components/extensions/Hosts/BulkActions/BulkChangeHostCollectionsModal/BulkChangeHostCollectionsModal.js +388 -0
  313. data/webpack/components/extensions/Hosts/BulkActions/BulkChangeHostCollectionsModal/__tests__/BulkChangeHostCollectionsModal.test.js +640 -0
  314. data/webpack/components/extensions/Hosts/BulkActions/BulkChangeHostCollectionsModal/actions.js +28 -0
  315. data/webpack/components/extensions/Hosts/BulkActions/BulkChangeHostCollectionsModal/index.js +71 -0
  316. data/webpack/components/extensions/Hosts/BulkActions/BulkErrataWizard/02_BulkErrataTable.js +1 -1
  317. data/webpack/components/extensions/Hosts/BulkActions/BulkErrataWizard/BulkErrataWizard.js +1 -1
  318. data/webpack/components/extensions/Hosts/BulkActions/BulkPackagesWizard/02_BulkPackagesTable.js +11 -4
  319. data/webpack/components/extensions/Hosts/BulkActions/BulkPackagesWizard/BulkPackagesWizard.js +51 -24
  320. data/webpack/components/extensions/Hosts/BulkActions/BulkRepositorySetsWizard/01_BulkRepositorySetsTable.js +1 -1
  321. data/webpack/components/extensions/Hosts/BulkActions/HostReview.js +8 -1
  322. data/webpack/containers/Application/config.js +11 -1
  323. data/webpack/global_index.js +3 -0
  324. data/webpack/scenes/{BootedContainerImages → ContainerImages/Booted}/BootedContainerImagesConstants.js +1 -1
  325. data/webpack/scenes/{BootedContainerImages → ContainerImages/Booted}/BootedContainerImagesPage.js +7 -43
  326. data/webpack/scenes/{BootedContainerImages → ContainerImages/Booted}/__tests__/bootedContainerImagesPage.test.js +1 -1
  327. data/webpack/scenes/ContainerImages/ContainerImagesPage.js +86 -0
  328. data/webpack/scenes/ContainerImages/LabelsAnnotationsModal.js +105 -0
  329. data/webpack/scenes/ContainerImages/Synced/Details/ManifestDetails.js +218 -0
  330. data/webpack/scenes/ContainerImages/Synced/Details/ManifestDetailsActions.js +15 -0
  331. data/webpack/scenes/ContainerImages/Synced/Details/ManifestDetailsSelectors.js +16 -0
  332. data/webpack/scenes/ContainerImages/Synced/Details/__tests__/ManifestDetails.test.js +395 -0
  333. data/webpack/scenes/ContainerImages/Synced/Details/__tests__/manifestDetails.fixtures.json +43 -0
  334. data/webpack/scenes/ContainerImages/Synced/Details/__tests__/manifestList.fixtures.json +58 -0
  335. data/webpack/scenes/ContainerImages/Synced/Details/index.js +4 -0
  336. data/webpack/scenes/ContainerImages/Synced/SyncedContainerImagesPage.js +359 -0
  337. data/webpack/scenes/ContainerImages/Synced/SyncedContainerImagesPage.scss +21 -0
  338. data/webpack/scenes/ContainerImages/Synced/__tests__/LabelsAnnotationsModal.test.js +69 -0
  339. data/webpack/scenes/ContainerImages/Synced/__tests__/SyncedContainerImagesPage.test.js +335 -0
  340. data/webpack/scenes/ContainerImages/Synced/__tests__/syncedContainerImages.fixtures.json +105 -0
  341. data/webpack/scenes/ContainerImages/TableEmptyState.js +67 -0
  342. data/webpack/scenes/ContainerImages/containerImagesHelpers.js +48 -0
  343. data/webpack/scenes/ContainerImages/index.js +4 -0
  344. data/webpack/scenes/ContentViews/Create/CreateContentViewForm.js +29 -3
  345. data/webpack/scenes/ContentViews/Create/__tests__/contentViewCreateResult.fixtures.json +1 -0
  346. data/webpack/scenes/ContentViews/Create/__tests__/createContentView.test.js +45 -1
  347. data/webpack/scenes/ContentViews/Delete/__tests__/affectedHosts.fixtures.json +0 -1
  348. data/webpack/scenes/ContentViews/Details/ContentViewInfo.js +59 -1
  349. data/webpack/scenes/ContentViews/Details/Filters/CVDebFilterContent.js +1 -0
  350. data/webpack/scenes/ContentViews/Details/Filters/Rules/DebPackage/AddEditDebPackageRuleModal.js +164 -24
  351. data/webpack/scenes/ContentViews/Details/Filters/__tests__/CVDebFilterContent.test.js +268 -0
  352. data/webpack/scenes/ContentViews/Details/Filters/__tests__/cvDebFilterDetail.fixtures.json +95 -0
  353. data/webpack/scenes/ContentViews/Details/Filters/__tests__/cvDebFilterRules.fixtures.json +31 -0
  354. data/webpack/scenes/ContentViews/Details/Filters/__tests__/emptyCVDebFilterRules.fixtures.json +10 -0
  355. data/webpack/scenes/ContentViews/Details/Versions/BulkDelete/__tests__/hosts.fixtures.json +0 -1
  356. data/webpack/scenes/ContentViews/Details/Versions/Delete/__tests__/cvAffectedHosts.fixture.json +0 -1
  357. data/webpack/scenes/ContentViews/Details/__tests__/contentViewRollingDetail.test.js +15 -0
  358. data/webpack/scenes/ContentViews/Details/__tests__/contentViewRollingDetails.fixtures.json +1 -0
  359. data/webpack/scenes/ContentViews/__tests__/contentViewPage.test.js +9 -0
  360. data/webpack/scenes/FlatpakRemotes/CreateEdit/CreateFlatpakRemoteModal.js +5 -3
  361. data/webpack/scenes/FlatpakRemotes/CreateEdit/EditFlatpakRemotesModal.js +1 -1
  362. data/webpack/scenes/FlatpakRemotes/CreateEdit/FlatpakRemoteform.js +35 -3
  363. data/webpack/scenes/FlatpakRemotes/Details/FlatpakRemoteDetails.js +1 -1
  364. data/webpack/scenes/FlatpakRemotes/Details/RemoteRepositories/RemoteRepositoriesTable.css +3 -0
  365. data/webpack/scenes/FlatpakRemotes/Details/RemoteRepositories/RemoteRepositoriesTable.js +63 -132
  366. data/webpack/scenes/FlatpakRemotes/FlatpakRemotesPage.js +67 -143
  367. data/webpack/scenes/SmartProxy/ExpandableCvDetails.js +10 -2
  368. data/webpack/scenes/SmartProxy/SmartProxyContentActions.js +13 -2
  369. data/webpack/scenes/SmartProxy/SmartProxyContentConstants.js +1 -0
  370. data/webpack/scenes/SmartProxy/SmartProxyExpandableTable.js +8 -2
  371. data/webpack/scenes/SmartProxy/__tests__/SmartProxyContentTest.js +67 -1
  372. data/webpack/scenes/Subscriptions/Details/__tests__/__snapshots__/SubscriptionDetails.test.js.snap +2 -2
  373. data/webpack/scenes/Subscriptions/SubscriptionConstants.js +0 -2
  374. data/webpack/scenes/Subscriptions/SubscriptionReducer.js +15 -5
  375. data/webpack/scenes/Subscriptions/SubscriptionsPage.js +22 -5
  376. data/webpack/scenes/Subscriptions/__tests__/SubscriptionsPage.test.js +141 -0
  377. data/webpack/scenes/Subscriptions/__tests__/__snapshots__/SubscriptionsActions.test.js.snap +2 -2
  378. metadata +82 -56
  379. data/app/lib/actions/katello/host/attach_subscriptions.rb +0 -59
  380. data/app/lib/actions/katello/host/auto_attach_subscriptions.rb +0 -22
  381. data/app/lib/actions/katello/host/remove_subscriptions.rb +0 -50
  382. data/app/lib/actions/katello/organization/simple_content_access/disable.rb +0 -25
  383. data/app/lib/actions/katello/organization/simple_content_access/enable.rb +0 -25
  384. data/app/lib/actions/katello/organization/simple_content_access/toggle.rb +0 -42
  385. data/lib/katello/tasks/migrate_structure_content_for_deb.rake +0 -105
  386. data/lib/katello/tasks/upgrades/4.2/remove_checksum_values.rake +0 -17
  387. /data/webpack/scenes/{BootedContainerImages → ContainerImages/Booted}/__tests__/bootedContainerImages.fixtures.js +0 -0
  388. /data/webpack/scenes/{BootedContainerImages → ContainerImages/Booted}/index.js +0 -0
@@ -12,6 +12,7 @@ import {
12
12
  FlexItem,
13
13
  Popover,
14
14
  Badge,
15
+ Button,
15
16
  DescriptionList,
16
17
  DescriptionListGroup,
17
18
  DescriptionListDescription as Dd,
@@ -206,9 +207,9 @@ const hostsIndexColumnExtensions = [
206
207
  </Flex>
207
208
  }
208
209
  >
209
- <FlexItem>
210
+ <Button variant="plain" style={{ padding: 0, color: 'inherit' }} ouiaId="content-view-environments-button">
210
211
  {truncate(contentViewEnvironments.map(cve => cve.label).join(', '), 35)}
211
- </FlexItem>
212
+ </Button>
212
213
  </Popover>
213
214
  </Flex>
214
215
  );
@@ -237,6 +238,49 @@ const hostsIndexColumnExtensions = [
237
238
  weight: 2600,
238
239
  isSorted: true,
239
240
  },
241
+ {
242
+ columnName: 'host_collections',
243
+ title: __('Host collections'),
244
+ wrapper: (hostDetails) => {
245
+ const hostCollections = hostDetails?.host_collections ?? [];
246
+ if (hostCollections.length === 0) return '—';
247
+
248
+ // Show count badge if more than one collection
249
+ if (hostCollections.length > 1) {
250
+ return (
251
+ <Flex>
252
+ <FlexItem>
253
+ <Badge isRead>{hostCollections.length}</Badge>
254
+ </FlexItem>
255
+ <Popover
256
+ id="host-collections-tooltip"
257
+ className="host-collections-tooltip"
258
+ maxWidth="34rem"
259
+ headerContent={hostDetails.display_name}
260
+ bodyContent={
261
+ <Flex direction={{ default: 'column' }}>
262
+ {hostCollections.map((hc, index) => (
263
+ <FlexItem key={hc.id}>
264
+ <Text component={TextVariants.p} ouiaId={`host-collection-name-${index}`}>{hc.name}</Text>
265
+ </FlexItem>
266
+ ))}
267
+ </Flex>
268
+ }
269
+ >
270
+ <Button variant="plain" style={{ padding: 0, color: 'inherit' }} ouiaId="host-collections-button">
271
+ {truncate(hostCollections.map(hc => hc.name).join(', '), 35)}
272
+ </Button>
273
+ </Popover>
274
+ </Flex>
275
+ );
276
+ }
277
+
278
+ // Just show the name if only one collection
279
+ return truncate(hostCollections[0].name, 35);
280
+ },
281
+ weight: 2700,
282
+ isSorted: false,
283
+ },
240
284
  ];
241
285
 
242
286
  hostsIndexColumnExtensions.forEach((column) => {
@@ -7,7 +7,7 @@ exports[`Content Details Info should render and contain appropriate components 1
7
7
  loadingText="Loading"
8
8
  timeout={300}
9
9
  >
10
- <Uncontrolled(TabContainer)
10
+ <ForwardRef
11
11
  defaultActiveKey={1}
12
12
  id="content-tabs-container"
13
13
  style={
@@ -137,7 +137,7 @@ exports[`Content Details Info should render and contain appropriate components 1
137
137
  </TabPane>
138
138
  </TabContent>
139
139
  </Grid>
140
- </Uncontrolled(TabContainer)>
140
+ </ForwardRef>
141
141
  </LoadingState>
142
142
  </div>
143
143
  `;
@@ -117,7 +117,6 @@ const SystemPurposeEditModal = ({
117
117
  dispatch(updateHostSysPurposeAttributes({
118
118
  id,
119
119
  attributes: {
120
- autoheal: true,
121
120
  purpose_role: optionsToValue(roleOptions, selectedRole),
122
121
  purpose_usage: optionsToValue(usageOptions, selectedUsage),
123
122
  release_version: optionsToValue(releaseVersionOptions, selectedReleaseVersion),
@@ -129,7 +128,6 @@ const SystemPurposeEditModal = ({
129
128
  dispatch(updateAKSysPurposeAttributes({
130
129
  id,
131
130
  attributes: {
132
- autoheal: true,
133
131
  purpose_role: optionsToValue(roleOptions, selectedRole),
134
132
  purpose_usage: optionsToValue(usageOptions, selectedUsage),
135
133
  release_version: optionsToValue(releaseVersionOptions, selectedReleaseVersion),
@@ -130,7 +130,6 @@ describe('SystemPurposeEditModal', () => {
130
130
  id: 1,
131
131
  host: {
132
132
  subscription_facet_attributes: {
133
- autoheal: true,
134
133
  // we're going to change role from 'Server' to 'Workstation'
135
134
  purpose_role: 'Red Hat Enterprise Linux Workstation',
136
135
  purpose_usage: 'Production',
@@ -187,7 +186,6 @@ describe('SystemPurposeEditModal', () => {
187
186
  id: 1,
188
187
  activation_key: {
189
188
  // we're going to change role from 'Server' to 'Workstation'
190
- autoheal: true,
191
189
  purpose_role: 'Red Hat Enterprise Linux Workstation',
192
190
  purpose_usage: 'Production',
193
191
  release_version: '8',
@@ -41,6 +41,7 @@ const HostActionsBar = () => {
41
41
  'bulk-packages-wizard',
42
42
  'bulk-errata-wizard',
43
43
  'bulk-repo-sets-wizard',
44
+ 'bulk-change-host-collections-modal',
44
45
  ].forEach((id) => {
45
46
  dispatch(addModal({ id }));
46
47
  });
@@ -0,0 +1,7 @@
1
+ const PACKAGE_CONTENT_TYPE_NAMES = {
2
+ INVALID: 'invalid',
3
+ DEBIAN: 'debs',
4
+ REDHAT: 'packages',
5
+ };
6
+
7
+ export default PACKAGE_CONTENT_TYPE_NAMES;
@@ -0,0 +1,388 @@
1
+ import React, { useState, useCallback } from 'react';
2
+ import PropTypes from 'prop-types';
3
+ import { useDispatch } from 'react-redux';
4
+ import { FormattedMessage } from 'react-intl';
5
+ import {
6
+ Modal,
7
+ Button,
8
+ Radio,
9
+ TextContent,
10
+ Text,
11
+ ToolbarItem,
12
+ } from '@patternfly/react-core';
13
+ import { ExclamationTriangleIcon } from '@patternfly/react-icons';
14
+ import { addToast } from 'foremanReact/components/ToastsList';
15
+ import { translate as __ } from 'foremanReact/common/I18n';
16
+ import { STATUS } from 'foremanReact/constants';
17
+ import { foremanUrl, noop } from 'foremanReact/common/helpers';
18
+ import { APIActions } from 'foremanReact/redux/API';
19
+ import {
20
+ HOSTS_API_PATH,
21
+ API_REQUEST_KEY,
22
+ } from 'foremanReact/routes/Hosts/constants';
23
+ import { useForemanOrganization } from 'foremanReact/Root/Context/ForemanContext';
24
+ import { useTableIndexAPIResponse, useSetParamsAndApiAndSearch } from 'foremanReact/components/PF4/TableIndexPage/Table/TableIndexHooks';
25
+ import { useBulkSelect } from 'foremanReact/components/PF4/TableIndexPage/Table/TableHooks';
26
+ import { getPageStats } from 'foremanReact/components/PF4/TableIndexPage/Table/helpers';
27
+ import TableIndexPage from 'foremanReact/components/PF4/TableIndexPage/TableIndexPage';
28
+ import { Table } from 'foremanReact/components/PF4/TableIndexPage/Table/Table';
29
+ import SelectAllCheckbox from 'foremanReact/components/PF4/TableIndexPage/Table/SelectAllCheckbox';
30
+ import {
31
+ bulkAddHostCollections,
32
+ bulkRemoveHostCollections,
33
+ } from './actions';
34
+ import katelloApi from '../../../../../services/api';
35
+
36
+ const BulkChangeHostCollectionsModal = ({
37
+ isOpen,
38
+ closeModal,
39
+ fetchBulkParams,
40
+ selectedCount: selectedHostsCount,
41
+ }) => {
42
+ const dispatch = useDispatch();
43
+ const [addRadioChecked, setAddRadioChecked] = useState(true);
44
+
45
+ const orgId = useForemanOrganization()?.id;
46
+ const DEFAULT_PER_PAGE = 5;
47
+ const hostCollectionsUrlForOrg =
48
+ katelloApi.getApiUrl(`/host_collections?per_page=${DEFAULT_PER_PAGE}&include_permissions=true&enabled=true&with_custom=true&organization_id=${orgId}`);
49
+ const apiOptions = { key: 'BULK_HOST_COLLECTIONS' };
50
+ const replacementResponse = isOpen ? false : { response: {} };
51
+
52
+ const hostCollectionsResponse = useTableIndexAPIResponse({
53
+ replacementResponse, // don't fetch data if modal is closed
54
+ apiUrl: hostCollectionsUrlForOrg,
55
+ apiOptions,
56
+ defaultParams: { per_page: DEFAULT_PER_PAGE },
57
+ });
58
+
59
+ const {
60
+ response: {
61
+ results: hostCollectionsResults,
62
+ ...hostCollectionsMetadata
63
+ },
64
+ setAPIOptions,
65
+ status: hostCollectionsLoadingStatus,
66
+ } = hostCollectionsResponse;
67
+
68
+ const {
69
+ total, page, subtotal, per_page: perPage,
70
+ } = hostCollectionsMetadata;
71
+
72
+ // Function to determine if a host collection row should be selectable
73
+ const isSelectableRow = useCallback((hc) => {
74
+ // When removing, all collections are selectable
75
+ if (!addRadioChecked) return true;
76
+
77
+ // When adding, check if there's enough space for the selected hosts
78
+ if (hc?.unlimited_hosts) return true; // Unlimited collections always have space
79
+
80
+ const currentHosts = Number(hc?.total_hosts || 0);
81
+ const maxHosts = Number(hc?.max_hosts || 0);
82
+ const availableSpace = maxHosts - currentHosts;
83
+
84
+ // Collection is selectable only if it has enough space for all selected hosts
85
+ return availableSpace >= selectedHostsCount;
86
+ }, [addRadioChecked, selectedHostsCount]);
87
+
88
+ const hostCollectionsBulkSelect = useBulkSelect({
89
+ results: hostCollectionsResults,
90
+ metadata: { total, page, selectable: subtotal },
91
+ isSelectable: isSelectableRow,
92
+ });
93
+
94
+ const {
95
+ setParamsAndAPI: setHostCollectionsParamsAndAPI,
96
+ } = useSetParamsAndApiAndSearch({
97
+ defaultParams: { search: '' },
98
+ apiOptions,
99
+ setAPIOptions,
100
+ updateSearchQuery: hostCollectionsBulkSelect.updateSearchQuery,
101
+ pushToHistory: false,
102
+ });
103
+
104
+ const {
105
+ selectNone,
106
+ selectOne,
107
+ selectPage,
108
+ isSelected,
109
+ selectedCount,
110
+ selectedResults,
111
+ areAllRowsSelected,
112
+ areAllRowsOnPageSelected,
113
+ updateSearchQuery,
114
+ } = hostCollectionsBulkSelect;
115
+
116
+ const pageStats = getPageStats({ total: subtotal, page, perPage });
117
+
118
+ // Handler for switching between Add/Remove modes
119
+ const handleRadioChange = (isAdd) => {
120
+ setAddRadioChecked(isAdd);
121
+
122
+ // If switching to "Add" mode, deselect any collections that don't have enough space
123
+ if (isAdd) {
124
+ selectedResults.forEach((hc) => {
125
+ if (!isSelectableRow(hc)) {
126
+ selectOne(false, hc.id);
127
+ }
128
+ });
129
+ }
130
+ };
131
+
132
+ // Derive selected IDs directly from selectedResults instead of storing in state
133
+ const HCIds = selectedResults.map(result => result.id);
134
+
135
+ const handleModalClose = () => {
136
+ setAddRadioChecked(true);
137
+ selectNone();
138
+ setHostCollectionsParamsAndAPI({ page: 1 });
139
+ closeModal();
140
+ };
141
+
142
+ const handleError = (error) => {
143
+ const message = error?.response?.data?.error?.message || __('An error occurred while updating host collections');
144
+ dispatch(addToast({ type: 'danger', message }));
145
+ };
146
+
147
+ const handleSuccess = (response) => {
148
+ const messages = response?.data?.displayMessages;
149
+ const message = Array.isArray(messages) && messages.length > 0
150
+ ? (
151
+ <>
152
+ {messages.map(msg => (
153
+ <div key={msg}>{msg}</div>
154
+ ))}
155
+ </>
156
+ )
157
+ : __('Host collections updated');
158
+
159
+ dispatch(addToast({ type: 'success', message }));
160
+ dispatch(APIActions.get({
161
+ key: API_REQUEST_KEY,
162
+ url: foremanUrl(HOSTS_API_PATH),
163
+ }));
164
+ handleModalClose();
165
+ };
166
+
167
+ const handleSave = () => {
168
+ const requestBody = {
169
+ included: {
170
+ search: fetchBulkParams(),
171
+ },
172
+ host_collection_ids: HCIds,
173
+ organization_id: orgId,
174
+ };
175
+
176
+ if (addRadioChecked) {
177
+ dispatch(bulkAddHostCollections(requestBody, handleSuccess, handleError));
178
+ } else {
179
+ dispatch(bulkRemoveHostCollections(requestBody, handleSuccess, handleError));
180
+ }
181
+ };
182
+
183
+ const isLoadingHostCollections = hostCollectionsLoadingStatus === STATUS.PENDING;
184
+ const isSaveDisabled = HCIds.length === 0 || isLoadingHostCollections;
185
+
186
+ // Selection toolbar
187
+ const selectionToolbar = (
188
+ <ToolbarItem key="selectAll">
189
+ <SelectAllCheckbox
190
+ {...{
191
+ selectAll: noop,
192
+ selectOne,
193
+ updateSearchQuery,
194
+ selectNone,
195
+ selectPage,
196
+ selectedCount,
197
+ pageRowCount: pageStats.pageRowCount,
198
+ areAllRowsSelected,
199
+ areAllRowsOnPageSelected,
200
+ }}
201
+ totalCount={total}
202
+ areAllRowsOnPageSelected={areAllRowsOnPageSelected()}
203
+ areAllRowsSelected={areAllRowsSelected()}
204
+ />
205
+ </ToolbarItem>
206
+ );
207
+
208
+ const modalActions = [
209
+ <Button
210
+ key="save"
211
+ ouiaId="bulk-change-host-collections-modal-save-button"
212
+ variant="primary"
213
+ onClick={handleSave}
214
+ isDisabled={isSaveDisabled}
215
+ isLoading={isLoadingHostCollections}
216
+ >
217
+ {__('Save')}
218
+ </Button>,
219
+ <Button
220
+ key="cancel"
221
+ ouiaId="bulk-change-host-collections-modal-cancel-button"
222
+ variant="link"
223
+ onClick={handleModalClose}
224
+ >
225
+ {__('Cancel')}
226
+ </Button>,
227
+ ];
228
+
229
+ const columns = {
230
+ name: {
231
+ title: __('Host collection'),
232
+ wrapper: hc => hc?.name || '',
233
+ isSorted: true,
234
+ weight: 50,
235
+ },
236
+ limit: {
237
+ title: __('Limit'),
238
+ wrapper: (hc) => {
239
+ const totalLimit = hc?.unlimited_hosts ? 'unlimited' : (hc?.max_hosts || 0);
240
+ const count = Number(hc?.total_hosts || 0);
241
+ const maxHosts = Number(hc?.max_hosts || 0);
242
+ const availableSpace = maxHosts - count;
243
+
244
+ // Show warning if collection doesn't have enough space for selected hosts (when adding)
245
+ const showWarning = addRadioChecked
246
+ && !hc?.unlimited_hosts
247
+ && availableSpace < selectedHostsCount;
248
+
249
+ return (
250
+ <>
251
+ {showWarning && (
252
+ <ExclamationTriangleIcon
253
+ color="var(--pf-v5-global--warning-color--100)"
254
+ style={{ marginRight: '8px' }}
255
+ aria-label={__('Insufficient space for selected hosts')}
256
+ />
257
+ )}
258
+ {`${count}/${totalLimit}`}
259
+ </>
260
+ );
261
+ },
262
+ isSorted: false,
263
+ weight: 100,
264
+ },
265
+ description: {
266
+ title: __('Description'),
267
+ wrapper: hc => hc?.description || '',
268
+ isSorted: false,
269
+ weight: 150,
270
+ },
271
+ };
272
+
273
+ return (
274
+ <Modal
275
+ isOpen={isOpen}
276
+ onClose={handleModalClose}
277
+ onEscapePress={handleModalClose}
278
+ title={__('Change host collections')}
279
+ width="60%"
280
+ position="top"
281
+ actions={modalActions}
282
+ id="bulk-update-host-collections-modal"
283
+ key="bulk-update-host-collections-modal"
284
+ ouiaId="bulk-update-host-collections-modal"
285
+ >
286
+ <TextContent>
287
+ <Text ouiaId="bulk-update-host-collections-text">
288
+ <FormattedMessage
289
+ defaultMessage={__('Select host collections to change their associations with {selectedHosts}. Changing host collection will affect all your selected hosts. Some hosts may already be in your chosen collections.')}
290
+ values={{
291
+ selectedHosts: (
292
+ <strong>
293
+ <FormattedMessage
294
+ defaultMessage="{count, plural, one {# {singular}} other {# {plural}}}"
295
+ values={{
296
+ count: selectedHostsCount,
297
+ singular: __('selected host'),
298
+ plural: __('selected hosts'),
299
+ }}
300
+ id="bulk-change-host-collections-selected-hosts"
301
+ />
302
+ </strong>
303
+ ),
304
+ }}
305
+ id="bulk-change-host-collections-description"
306
+ />
307
+ </Text>
308
+ </TextContent>
309
+ <h3><strong>{__('Select action')}</strong></h3>
310
+ <div style={{ display: 'flex', alignItems: 'baseline' }}>
311
+ <Radio
312
+ isChecked={addRadioChecked}
313
+ onChange={(_e, checked) => handleRadioChange(checked)}
314
+ name="radio-add"
315
+ label={__('Add to host collections')}
316
+ id="radio-add-action"
317
+ ouiaId="radio-add-action"
318
+ />
319
+ <Radio
320
+ isChecked={!addRadioChecked}
321
+ onChange={(_e, checked) => handleRadioChange(!checked)}
322
+ name="radio-remove"
323
+ label={__('Remove from host collections')}
324
+ id="radio-remove-action"
325
+ ouiaId="radio-remove-action"
326
+ style={{ marginLeft: '50px' }}
327
+ />
328
+ </div>
329
+ <div>
330
+ <TableIndexPage
331
+ selectionToolbar={selectionToolbar}
332
+ results={hostCollectionsResults}
333
+ metadata={hostCollectionsMetadata}
334
+ response={hostCollectionsResponse}
335
+ tableType="host_collections"
336
+ apiUrl={hostCollectionsUrlForOrg}
337
+ apiOptions={apiOptions}
338
+ selectedCount={selectedCount}
339
+ selectPage={selectPage}
340
+ selectNone={selectNone}
341
+ customSearchProps={{
342
+ autocomplete: {
343
+ url: katelloApi.getApiUrl('/host_collections/auto_complete_search'),
344
+ },
345
+ }}
346
+ bulkSelect={hostCollectionsBulkSelect}
347
+ updateParamsByUrl={false}
348
+ isSelectableRow={isSelectableRow}
349
+ >
350
+ <Table
351
+ showCheckboxes
352
+ selectOne={selectOne}
353
+ isSelected={isSelected}
354
+ isSelectable={isSelectableRow}
355
+ isEmbedded
356
+ idColumn="id"
357
+ columns={columns}
358
+ refreshData={noop}
359
+ url=""
360
+ results={hostCollectionsResults}
361
+ isPending={hostCollectionsLoadingStatus === STATUS.PENDING}
362
+ params={{ ...hostCollectionsMetadata, perPage, page }}
363
+ setParams={setHostCollectionsParamsAndAPI}
364
+ page={page}
365
+ perPage={perPage}
366
+ itemCount={subtotal}
367
+ />
368
+ </TableIndexPage>
369
+ </div>
370
+ </Modal>
371
+ );
372
+ };
373
+
374
+ BulkChangeHostCollectionsModal.propTypes = {
375
+ isOpen: PropTypes.bool,
376
+ closeModal: PropTypes.func,
377
+ fetchBulkParams: PropTypes.func,
378
+ selectedCount: PropTypes.number,
379
+ };
380
+
381
+ BulkChangeHostCollectionsModal.defaultProps = {
382
+ isOpen: false,
383
+ closeModal: () => {},
384
+ fetchBulkParams: () => '',
385
+ selectedCount: 0,
386
+ };
387
+
388
+ export default BulkChangeHostCollectionsModal;