katello 4.15.0 → 4.16.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 (513) hide show
  1. checksums.yaml +4 -4
  2. data/app/assets/javascripts/katello/common/katello_object.js +2 -2
  3. data/app/assets/javascripts/katello/hosts/host_and_hostgroup_edit.js +9 -8
  4. data/app/assets/javascripts/katello/locale/bn/katello.js +248 -263
  5. data/app/assets/javascripts/katello/locale/bn_IN/katello.js +247 -262
  6. data/app/assets/javascripts/katello/locale/ca/katello.js +247 -262
  7. data/app/assets/javascripts/katello/locale/cs/katello.js +521 -536
  8. data/app/assets/javascripts/katello/locale/cs_CZ/katello.js +253 -268
  9. data/app/assets/javascripts/katello/locale/de/katello.js +248 -263
  10. data/app/assets/javascripts/katello/locale/de_AT/katello.js +247 -262
  11. data/app/assets/javascripts/katello/locale/de_DE/katello.js +249 -264
  12. data/app/assets/javascripts/katello/locale/el/katello.js +251 -266
  13. data/app/assets/javascripts/katello/locale/en/katello.js +253 -268
  14. data/app/assets/javascripts/katello/locale/en_GB/katello.js +263 -278
  15. data/app/assets/javascripts/katello/locale/en_US/katello.js +247 -262
  16. data/app/assets/javascripts/katello/locale/es/katello.js +248 -263
  17. data/app/assets/javascripts/katello/locale/et_EE/katello.js +247 -262
  18. data/app/assets/javascripts/katello/locale/fr/katello.js +250 -265
  19. data/app/assets/javascripts/katello/locale/gl/katello.js +247 -262
  20. data/app/assets/javascripts/katello/locale/gu/katello.js +249 -264
  21. data/app/assets/javascripts/katello/locale/he_IL/katello.js +249 -264
  22. data/app/assets/javascripts/katello/locale/hi/katello.js +248 -263
  23. data/app/assets/javascripts/katello/locale/id/katello.js +261 -275
  24. data/app/assets/javascripts/katello/locale/it/katello.js +252 -267
  25. data/app/assets/javascripts/katello/locale/ja/katello.js +250 -265
  26. data/app/assets/javascripts/katello/locale/ka/katello.js +247 -262
  27. data/app/assets/javascripts/katello/locale/kn/katello.js +248 -263
  28. data/app/assets/javascripts/katello/locale/ko/katello.js +248 -263
  29. data/app/assets/javascripts/katello/locale/ml_IN/katello.js +247 -262
  30. data/app/assets/javascripts/katello/locale/mr/katello.js +248 -263
  31. data/app/assets/javascripts/katello/locale/nl_NL/katello.js +252 -267
  32. data/app/assets/javascripts/katello/locale/or/katello.js +248 -263
  33. data/app/assets/javascripts/katello/locale/pa/katello.js +248 -263
  34. data/app/assets/javascripts/katello/locale/pl/katello.js +248 -263
  35. data/app/assets/javascripts/katello/locale/pl_PL/katello.js +247 -262
  36. data/app/assets/javascripts/katello/locale/pt/katello.js +248 -263
  37. data/app/assets/javascripts/katello/locale/pt_BR/katello.js +248 -263
  38. data/app/assets/javascripts/katello/locale/ro/katello.js +247 -262
  39. data/app/assets/javascripts/katello/locale/ro_RO/katello.js +247 -262
  40. data/app/assets/javascripts/katello/locale/ru/katello.js +253 -268
  41. data/app/assets/javascripts/katello/locale/sl/katello.js +247 -262
  42. data/app/assets/javascripts/katello/locale/sv_SE/katello.js +248 -263
  43. data/app/assets/javascripts/katello/locale/ta/katello.js +248 -263
  44. data/app/assets/javascripts/katello/locale/ta_IN/katello.js +247 -262
  45. data/app/assets/javascripts/katello/locale/te/katello.js +248 -263
  46. data/app/assets/javascripts/katello/locale/tr/katello.js +247 -262
  47. data/app/assets/javascripts/katello/locale/vi/katello.js +247 -262
  48. data/app/assets/javascripts/katello/locale/vi_VN/katello.js +247 -262
  49. data/app/assets/javascripts/katello/locale/zh/katello.js +247 -262
  50. data/app/assets/javascripts/katello/locale/zh_CN/katello.js +250 -265
  51. data/app/assets/javascripts/katello/locale/zh_TW/katello.js +255 -270
  52. data/app/assets/javascripts/katello/sync_management/sync_management.js +16 -2
  53. data/app/controllers/katello/api/registry/registry_proxies_controller.rb +46 -10
  54. data/app/controllers/katello/api/rhsm/candlepin_proxies_controller.rb +1 -1
  55. data/app/controllers/katello/api/v2/activation_keys_controller.rb +4 -9
  56. data/app/controllers/katello/api/v2/content_uploads_controller.rb +2 -1
  57. data/app/controllers/katello/api/v2/content_view_filter_rules_controller.rb +3 -1
  58. data/app/controllers/katello/api/v2/content_views_controller.rb +4 -1
  59. data/app/controllers/katello/api/v2/environments_controller.rb +4 -0
  60. data/app/controllers/katello/api/v2/errata_controller.rb +12 -1
  61. data/app/controllers/katello/api/v2/flatpak_remote_repositories_controller.rb +81 -0
  62. data/app/controllers/katello/api/v2/flatpak_remotes_controller.rb +86 -0
  63. data/app/controllers/katello/api/v2/host_bootc_images_controller.rb +71 -0
  64. data/app/controllers/katello/api/v2/host_subscriptions_controller.rb +4 -6
  65. data/app/controllers/katello/api/v2/hosts_bulk_actions_controller.rb +3 -5
  66. data/app/controllers/katello/api/v2/repositories_controller.rb +18 -3
  67. data/app/controllers/katello/concerns/api/v2/hosts_controller_extensions.rb +0 -8
  68. data/app/controllers/katello/concerns/api/v2/http_proxies_controller_extensions.rb +17 -0
  69. data/app/controllers/katello/concerns/http_proxies_controller_extensions.rb +20 -0
  70. data/app/controllers/katello/sync_management_controller.rb +6 -2
  71. data/app/helpers/katello/content_source_helper.rb +8 -1
  72. data/app/helpers/katello/content_view_helper.rb +3 -1
  73. data/app/lib/actions/candlepin/activation_key/create.rb +1 -3
  74. data/app/lib/actions/candlepin/activation_key/update.rb +1 -3
  75. data/app/lib/actions/candlepin/environment/set_content.rb +17 -4
  76. data/app/lib/actions/katello/activation_key/create.rb +1 -2
  77. data/app/lib/actions/katello/activation_key/update.rb +2 -4
  78. data/app/lib/actions/katello/capsule_content/refresh_repos.rb +7 -1
  79. data/app/lib/actions/katello/content_view/presenters/incremental_updates_presenter.rb +3 -2
  80. data/app/lib/actions/katello/content_view/publish.rb +7 -2
  81. data/app/lib/actions/katello/content_view_environment/reassign_objects.rb +11 -2
  82. data/app/lib/actions/katello/content_view_version/incremental_update.rb +31 -22
  83. data/app/lib/actions/katello/flatpak/mirror_remote_repository.rb +30 -0
  84. data/app/lib/actions/katello/flatpak/scan_remote.rb +17 -12
  85. data/app/lib/actions/katello/host/update_system_purpose.rb +1 -6
  86. data/app/lib/actions/pulp3/orchestration/repository/import_upload.rb +18 -2
  87. data/app/lib/actions/pulp3/orchestration/repository/multi_copy_all_units.rb +5 -0
  88. data/app/lib/actions/pulp3/repository/multi_copy_units.rb +4 -0
  89. data/app/lib/katello/api/v2/rendering.rb +2 -1
  90. data/app/lib/katello/concerns/base_template_scope_extensions.rb +3 -4
  91. data/app/lib/katello/concerns/bookmark_controller_validator_extensions.rb +13 -0
  92. data/app/lib/katello/resources/candlepin/activation_key.rb +3 -5
  93. data/app/lib/katello/resources/candlepin/product.rb +2 -1
  94. data/app/lib/katello/util/cveak_migrator.rb +3 -2
  95. data/app/lib/katello/validators/alternate_content_source_path_validator.rb +2 -2
  96. data/app/lib/katello/validators/container_image_name_validator.rb +1 -1
  97. data/app/lib/katello/validators/content_validator.rb +1 -1
  98. data/app/lib/katello/validators/content_view_environment_coherent_default_validator.rb +2 -2
  99. data/app/lib/katello/validators/content_view_environment_org_validator.rb +2 -2
  100. data/app/lib/katello/validators/content_view_environment_validator.rb +3 -3
  101. data/app/lib/katello/validators/content_view_erratum_filter_rule_validator.rb +12 -12
  102. data/app/lib/katello/validators/content_view_filter_version_validator.rb +1 -1
  103. data/app/lib/katello/validators/generated_content_view_validator.rb +1 -1
  104. data/app/lib/katello/validators/gpg_key_content_type_validator.rb +2 -2
  105. data/app/lib/katello/validators/gpg_key_content_validator.rb +5 -5
  106. data/app/lib/katello/validators/katello_label_format_validator.rb +4 -4
  107. data/app/lib/katello/validators/katello_name_format_validator.rb +2 -2
  108. data/app/lib/katello/validators/katello_url_format_validator.rb +1 -1
  109. data/app/lib/katello/validators/library_presence_validator.rb +1 -1
  110. data/app/lib/katello/validators/no_trailing_space_validator.rb +1 -1
  111. data/app/lib/katello/validators/non_library_environment_validator.rb +1 -1
  112. data/app/lib/katello/validators/not_in_library_validator.rb +1 -1
  113. data/app/lib/katello/validators/path_descendents_validator.rb +1 -1
  114. data/app/lib/katello/validators/prior_validator.rb +1 -1
  115. data/app/lib/katello/validators/product_unique_attribute_validator.rb +1 -1
  116. data/app/lib/katello/validators/repo_disablement_validator.rb +2 -2
  117. data/app/lib/katello/validators/root_repository_unique_attribute_validator.rb +1 -1
  118. data/app/lib/katello/validators/self_reference_environment_validator.rb +1 -1
  119. data/app/lib/katello/validators/unique_field_in_org.rb +1 -1
  120. data/app/models/katello/activation_key.rb +6 -17
  121. data/app/models/katello/authorization/flatpak_remote.rb +33 -0
  122. data/app/models/katello/concerns/content_facet_host_extensions.rb +2 -1
  123. data/app/models/katello/concerns/host_managed_extensions.rb +8 -5
  124. data/app/models/katello/concerns/http_proxy_extensions.rb +4 -0
  125. data/app/models/katello/concerns/smart_proxy_extensions.rb +30 -6
  126. data/app/models/katello/concerns/subscription_facet_host_extensions.rb +0 -8
  127. data/app/models/katello/content_view.rb +6 -4
  128. data/app/models/katello/content_view_erratum_filter.rb +18 -2
  129. data/app/models/katello/content_view_version.rb +6 -0
  130. data/app/models/katello/docker_manifest.rb +8 -0
  131. data/app/models/katello/docker_manifest_list.rb +8 -0
  132. data/app/models/katello/erratum.rb +8 -2
  133. data/app/models/katello/flatpak_remote.rb +16 -0
  134. data/app/models/katello/flatpak_remote_repository.rb +18 -0
  135. data/app/models/katello/flatpak_remote_repository_manifest.rb +4 -0
  136. data/app/models/katello/glue/candlepin/pool.rb +1 -1
  137. data/app/models/katello/glue/pulp/repos.rb +12 -1
  138. data/app/models/katello/host/content_facet.rb +42 -3
  139. data/app/models/katello/host/subscription_facet.rb +4 -12
  140. data/app/models/katello/repository.rb +22 -8
  141. data/app/models/katello/rhel_lifecycle_status.rb +6 -0
  142. data/app/models/katello/root_repository.rb +6 -8
  143. data/app/models/katello/upstream_pool.rb +1 -0
  144. data/app/overrides/add_organization_attributes.rb +6 -0
  145. data/app/services/katello/product_content_finder.rb +2 -1
  146. data/app/services/katello/pulp3/content_view_version/importable_repositories.rb +1 -1
  147. data/app/services/katello/pulp3/docker_manifest.rb +3 -2
  148. data/app/services/katello/pulp3/docker_manifest_list.rb +3 -2
  149. data/app/services/katello/pulp3/repository/ansible_collection.rb +8 -1
  150. data/app/services/katello/pulp3/repository/apt.rb +37 -21
  151. data/app/services/katello/pulp3/repository/file.rb +4 -2
  152. data/app/services/katello/pulp3/repository.rb +4 -0
  153. data/app/services/katello/pulp3/task.rb +2 -2
  154. data/app/views/foreman/job_templates/bootc_action.erb +26 -0
  155. data/app/views/foreman/job_templates/bootc_rollback.erb +13 -0
  156. data/app/views/foreman/job_templates/bootc_status.erb +13 -0
  157. data/app/views/foreman/job_templates/bootc_switch.erb +13 -0
  158. data/app/views/foreman/job_templates/bootc_upgrade.erb +13 -0
  159. data/app/views/foreman/job_templates/flatpak_install.erb +23 -0
  160. data/app/views/foreman/job_templates/flatpak_login_action.erb +30 -0
  161. data/app/views/foreman/job_templates/flatpak_setup.erb +27 -0
  162. data/app/views/foreman/job_templates/install_errata_by_search_query.erb +1 -1
  163. data/app/views/foreman/job_templates/install_errata_by_search_query_-_katello_ansible_default.erb +1 -1
  164. data/app/views/foreman/job_templates/resolve_traces_-_katello_ansible_default.erb +1 -1
  165. data/app/views/foreman/job_templates/update_packages_by_search_query_-_katello_ansible_default.erb +1 -1
  166. data/app/views/katello/api/v2/activation_keys/base.json.rabl +0 -4
  167. data/app/views/katello/api/v2/content_facet/base.json.rabl +2 -1
  168. data/app/views/katello/api/v2/content_facet/show.json.rabl +2 -0
  169. data/app/views/katello/api/v2/content_view_filter_rules/show.json.rabl +1 -0
  170. data/app/views/katello/api/v2/content_view_versions/base.json.rabl +5 -1
  171. data/app/views/katello/api/v2/docker_manifest_lists/show.json.rabl +1 -1
  172. data/app/views/katello/api/v2/docker_manifests/show.json.rabl +1 -1
  173. data/app/views/katello/api/v2/flatpak_remote_repositories/base.json.rabl +4 -0
  174. data/app/views/katello/api/v2/flatpak_remote_repositories/index.json.rabl +7 -0
  175. data/app/views/katello/api/v2/flatpak_remote_repositories/show.json.rabl +13 -0
  176. data/app/views/katello/api/v2/flatpak_remotes/base.json.rabl +5 -0
  177. data/app/views/katello/api/v2/flatpak_remotes/index.json.rabl +8 -0
  178. data/app/views/katello/api/v2/flatpak_remotes/permissions.json.rabl +11 -0
  179. data/app/views/katello/api/v2/flatpak_remotes/show.json.rabl +3 -0
  180. data/app/views/katello/api/v2/hosts/base.json.rabl +0 -8
  181. data/app/views/katello/api/v2/hosts/os_attributes.json.rabl +13 -0
  182. data/app/views/katello/api/v2/http_proxies/show.json.rabl +1 -0
  183. data/app/views/katello/api/v2/repositories/base.json.rabl +1 -0
  184. data/app/views/katello/api/v2/repositories/show.json.rabl +1 -0
  185. data/app/views/katello/api/v2/subscription_facet/base.json.rabl +0 -4
  186. data/app/views/katello/api/v2/subscriptions/show.json.rabl +1 -1
  187. data/app/views/overrides/activation_keys/_host_environment_select.html.erb +2 -1
  188. data/app/views/overrides/activation_keys/_host_synced_content_select.html.erb +10 -4
  189. data/app/views/overrides/http_proxies/_update_setting_input.html.erb +18 -0
  190. data/app/views/overrides/organizations/_step_1_override.html.erb +5 -0
  191. data/config/initializers/monkeys.rb +0 -1
  192. data/config/initializers/pagelets.rb +6 -0
  193. data/config/routes/api/registry.rb +1 -0
  194. data/config/routes/api/v2.rb +21 -0
  195. data/config/routes/overrides.rb +1 -0
  196. data/config/routes.rb +2 -0
  197. data/db/migrate/20190605014649_add_purpose_addons.rb +0 -12
  198. data/db/migrate/20200213184848_create_evr_type.rb +126 -1
  199. data/db/migrate/20200818192230_update_system_purpose_status.rb +0 -1
  200. data/db/migrate/20240207191223_remove_entitlement_mode_host_statuses.rb +0 -1
  201. data/db/migrate/20240924161240_katello_recreate_evr_constructs.rb +160 -0
  202. data/db/migrate/20241022121706_add_sync_dependencies_option.rb +5 -0
  203. data/db/migrate/20241101144625_remove_system_purpose_addons.rb +9 -0
  204. data/db/migrate/20241107002541_add_registry_url_to_katello_flatpak_remotes.rb +5 -0
  205. data/db/migrate/20241112145802_add_manifest_entity_to_content_facets.rb +7 -0
  206. data/db/migrate/20241120213713_add_allow_other_types_to_content_view_erratum_filter_rules.rb +6 -0
  207. data/db/migrate/20241206183052_add_content_type_to_container_manifests_and_lists.rb +9 -0
  208. data/db/seeds.d/75-job_templates.rb +5 -1
  209. data/engines/bastion/vendor/assets/javascripts/bastion/angular/angular.js +2 -2
  210. data/engines/bastion/vendor/assets/javascripts/bastion/angular-bootstrap/ui-bootstrap-tpls.js +3 -3
  211. data/engines/bastion/vendor/assets/javascripts/bastion/angular-bootstrap/ui-bootstrap.js +3 -3
  212. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/activation-keys/details/activation-key-details-info.controller.js +0 -5
  213. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/activation-keys/details/activation-key-details.controller.js +1 -41
  214. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/activation-keys/details/views/activation-key-info.html +0 -12
  215. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/activation-keys/new/views/activation-key-new.html +2 -1
  216. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/common/views/subscription-add-or-remove.html +1 -1
  217. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/content-hosts/bulk/content-hosts-bulk-release-version-modal.controller.js +3 -1
  218. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/content-hosts/bulk/content-hosts-bulk-system-purpose-modal.controller.js +1 -41
  219. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/content-hosts/bulk/content-hosts-bulk-traces-modal.controller.js +1 -1
  220. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/content-hosts/bulk/views/content-hosts-bulk-errata-modal.html +2 -2
  221. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/content-hosts/bulk/views/content-hosts-bulk-release-version-modal.html +1 -1
  222. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/content-hosts/bulk/views/content-hosts-bulk-subscriptions-modal.html +2 -2
  223. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/content-hosts/bulk/views/content-hosts-bulk-system-purpose-modal.html +0 -13
  224. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/content-hosts/content/views/content-host-errata.html +1 -1
  225. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/content-hosts/details/content-host-details-info.controller.js +0 -5
  226. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/content-hosts/details/content-host-details.controller.js +1 -35
  227. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/content-hosts/details/views/content-host-info.html +2 -14
  228. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/content-hosts/details/views/content-host-provisioning-info.html +1 -1
  229. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/content-hosts/views/content-hosts.html +2 -2
  230. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/debs/debs.controller.js +46 -22
  231. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/debs/details/deb-content-views.controller.js +2 -1
  232. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/debs/views/debs.html +4 -0
  233. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/environments/details/views/environment-content-views.html +1 -1
  234. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/environments/details/views/environment-details.html +1 -1
  235. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/environments/details/views/environment-errata.html +1 -1
  236. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/errata/views/errata-tasks-list.html +2 -1
  237. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/i18n/bastion_katello.pot +85 -29
  238. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/i18n/locale/bn.po +338 -93
  239. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/i18n/locale/bn_IN.po +340 -95
  240. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/i18n/locale/ca.po +340 -95
  241. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/i18n/locale/cs_CZ.po +341 -96
  242. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/i18n/locale/de.po +31 -54
  243. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/i18n/locale/de_AT.po +338 -93
  244. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/i18n/locale/de_DE.po +338 -93
  245. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/i18n/locale/el.po +341 -96
  246. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/i18n/locale/en_GB.po +349 -104
  247. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/i18n/locale/en_US.po +338 -93
  248. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/i18n/locale/es.po +33 -56
  249. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/i18n/locale/et_EE.po +338 -93
  250. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/i18n/locale/fr.po +80 -68
  251. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/i18n/locale/gl.po +340 -95
  252. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/i18n/locale/gu.po +340 -95
  253. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/i18n/locale/he_IL.po +339 -111
  254. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/i18n/locale/hi.po +340 -95
  255. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/i18n/locale/id.po +379 -130
  256. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/i18n/locale/it.po +342 -103
  257. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/i18n/locale/ja.po +70 -83
  258. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/i18n/locale/ka.po +84 -90
  259. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/i18n/locale/kn.po +340 -95
  260. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/i18n/locale/ko.po +130 -138
  261. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/i18n/locale/ml_IN.po +338 -93
  262. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/i18n/locale/mr.po +340 -95
  263. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/i18n/locale/nl_NL.po +343 -97
  264. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/i18n/locale/or.po +340 -95
  265. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/i18n/locale/pa.po +340 -95
  266. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/i18n/locale/pl.po +340 -95
  267. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/i18n/locale/pl_PL.po +338 -93
  268. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/i18n/locale/pt.po +338 -93
  269. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/i18n/locale/pt_BR.po +40 -63
  270. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/i18n/locale/ro.po +338 -93
  271. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/i18n/locale/ro_RO.po +338 -93
  272. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/i18n/locale/ru.po +343 -102
  273. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/i18n/locale/sl.po +338 -93
  274. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/i18n/locale/sv_SE.po +340 -95
  275. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/i18n/locale/ta.po +338 -93
  276. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/i18n/locale/ta_IN.po +340 -95
  277. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/i18n/locale/te.po +340 -95
  278. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/i18n/locale/tr.po +338 -93
  279. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/i18n/locale/vi.po +338 -93
  280. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/i18n/locale/vi_VN.po +338 -93
  281. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/i18n/locale/zh.po +338 -93
  282. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/i18n/locale/zh_CN.po +70 -83
  283. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/i18n/locale/zh_TW.po +362 -105
  284. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/i18n/translations.js +29 -29
  285. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/packages/details/views/package-info.html +1 -1
  286. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/products/bulk/products-bulk-advanced-sync-modal.controller.js +1 -1
  287. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/products/bulk/views/products-bulk-sync-plan-modal.html +2 -2
  288. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/products/details/repositories/details/views/repository-info.html +24 -8
  289. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/products/details/repositories/details/views/repository-tasks.html +2 -1
  290. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/products/details/repositories/new/new-repository.controller.js +2 -2
  291. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/products/details/repositories/new/views/new-repository.html +21 -8
  292. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/products/details/repositories/os-versions.service.js +1 -0
  293. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/products/details/views/product-info.html +3 -3
  294. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/products/details/views/product-tasks.html +2 -1
  295. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/products/discovery/views/discovery-create.html +4 -2
  296. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/products/discovery/views/discovery.html +2 -1
  297. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/products/products.controller.js +3 -3
  298. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/products/views/partials/product-table-sync-status.html +1 -1
  299. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/subscriptions/views/subscription-start-date.html +1 -1
  300. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/sync-plans/details/views/sync-plan-info.html +1 -1
  301. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/sync-plans/views/sync-plans.html +2 -2
  302. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/tasks/tasks-table.directive.js +2 -1
  303. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/tasks/views/task-details.html +2 -2
  304. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/tasks/views/tasks-index.html +1 -1
  305. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/tasks/views/tasks-table.html +1 -1
  306. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/tasks/views/user-tasks-table.html +1 -1
  307. data/lib/katello/engine.rb +6 -0
  308. data/lib/katello/permission_creator.rb +37 -0
  309. data/lib/katello/permissions/host_permissions.rb +2 -0
  310. data/lib/katello/permissions/registry_permissions.rb +1 -0
  311. data/lib/katello/plugin.rb +18 -1
  312. data/lib/katello/repository_types/docker.rb +0 -1
  313. data/lib/katello/repository_types/python.rb +1 -1
  314. data/lib/katello/version.rb +1 -1
  315. data/lib/katello.rb +2 -0
  316. data/locale/Makefile +20 -24
  317. data/locale/bn/LC_MESSAGES/katello.mo +0 -0
  318. data/locale/bn/katello.po +248 -263
  319. data/locale/bn_IN/LC_MESSAGES/katello.mo +0 -0
  320. data/locale/bn_IN/katello.po +247 -262
  321. data/locale/ca/LC_MESSAGES/katello.mo +0 -0
  322. data/locale/ca/katello.po +247 -262
  323. data/locale/cs/LC_MESSAGES/katello.mo +0 -0
  324. data/locale/cs/katello.po +524 -799
  325. data/locale/cs_CZ/LC_MESSAGES/katello.mo +0 -0
  326. data/locale/cs_CZ/katello.po +254 -269
  327. data/locale/de/LC_MESSAGES/katello.mo +0 -0
  328. data/locale/de/katello.po +248 -263
  329. data/locale/de_AT/LC_MESSAGES/katello.mo +0 -0
  330. data/locale/de_AT/katello.po +247 -262
  331. data/locale/de_DE/LC_MESSAGES/katello.mo +0 -0
  332. data/locale/de_DE/katello.po +250 -265
  333. data/locale/el/LC_MESSAGES/katello.mo +0 -0
  334. data/locale/el/katello.po +252 -267
  335. data/locale/en/LC_MESSAGES/katello.mo +0 -0
  336. data/locale/en/katello.po +257 -271
  337. data/locale/en_GB/LC_MESSAGES/katello.mo +0 -0
  338. data/locale/en_GB/katello.po +264 -279
  339. data/locale/en_US/LC_MESSAGES/katello.mo +0 -0
  340. data/locale/en_US/katello.po +247 -262
  341. data/locale/es/LC_MESSAGES/katello.mo +0 -0
  342. data/locale/es/katello.po +248 -263
  343. data/locale/et_EE/LC_MESSAGES/katello.mo +0 -0
  344. data/locale/et_EE/katello.po +247 -262
  345. data/locale/fr/LC_MESSAGES/katello.mo +0 -0
  346. data/locale/fr/katello.po +250 -265
  347. data/locale/gl/LC_MESSAGES/katello.mo +0 -0
  348. data/locale/gl/katello.po +247 -262
  349. data/locale/gu/LC_MESSAGES/katello.mo +0 -0
  350. data/locale/gu/katello.po +250 -265
  351. data/locale/he_IL/LC_MESSAGES/katello.mo +0 -0
  352. data/locale/he_IL/katello.po +249 -264
  353. data/locale/hi/LC_MESSAGES/katello.mo +0 -0
  354. data/locale/hi/katello.po +248 -263
  355. data/locale/id/LC_MESSAGES/katello.mo +0 -0
  356. data/locale/id/katello.po +264 -275
  357. data/locale/it/LC_MESSAGES/katello.mo +0 -0
  358. data/locale/it/katello.po +254 -270
  359. data/locale/ja/LC_MESSAGES/katello.mo +0 -0
  360. data/locale/ja/katello.po +250 -265
  361. data/locale/ka/LC_MESSAGES/katello.mo +0 -0
  362. data/locale/ka/katello.po +247 -262
  363. data/locale/katello.pot +1216 -1215
  364. data/locale/kn/LC_MESSAGES/katello.mo +0 -0
  365. data/locale/kn/katello.po +248 -263
  366. data/locale/ko/LC_MESSAGES/katello.mo +0 -0
  367. data/locale/ko/katello.po +248 -263
  368. data/locale/ml_IN/LC_MESSAGES/katello.mo +0 -0
  369. data/locale/ml_IN/katello.po +247 -262
  370. data/locale/mr/LC_MESSAGES/katello.mo +0 -0
  371. data/locale/mr/katello.po +248 -263
  372. data/locale/nl_NL/LC_MESSAGES/katello.mo +0 -0
  373. data/locale/nl_NL/katello.po +254 -268
  374. data/locale/or/LC_MESSAGES/katello.mo +0 -0
  375. data/locale/or/katello.po +248 -263
  376. data/locale/pa/LC_MESSAGES/katello.mo +0 -0
  377. data/locale/pa/katello.po +248 -263
  378. data/locale/pl/LC_MESSAGES/katello.mo +0 -0
  379. data/locale/pl/katello.po +249 -264
  380. data/locale/pl_PL/LC_MESSAGES/katello.mo +0 -0
  381. data/locale/pl_PL/katello.po +247 -262
  382. data/locale/pt/LC_MESSAGES/katello.mo +0 -0
  383. data/locale/pt/katello.po +248 -263
  384. data/locale/pt_BR/LC_MESSAGES/katello.mo +0 -0
  385. data/locale/pt_BR/katello.po +248 -263
  386. data/locale/ro/LC_MESSAGES/katello.mo +0 -0
  387. data/locale/ro/katello.po +247 -262
  388. data/locale/ro_RO/LC_MESSAGES/katello.mo +0 -0
  389. data/locale/ro_RO/katello.po +247 -262
  390. data/locale/ru/LC_MESSAGES/katello.mo +0 -0
  391. data/locale/ru/katello.po +255 -270
  392. data/locale/sl/LC_MESSAGES/katello.mo +0 -0
  393. data/locale/sl/katello.po +247 -262
  394. data/locale/sv_SE/LC_MESSAGES/katello.mo +0 -0
  395. data/locale/sv_SE/katello.po +249 -264
  396. data/locale/ta/LC_MESSAGES/katello.mo +0 -0
  397. data/locale/ta/katello.po +248 -263
  398. data/locale/ta_IN/LC_MESSAGES/katello.mo +0 -0
  399. data/locale/ta_IN/katello.po +247 -262
  400. data/locale/te/LC_MESSAGES/katello.mo +0 -0
  401. data/locale/te/katello.po +248 -263
  402. data/locale/tr/LC_MESSAGES/katello.mo +0 -0
  403. data/locale/tr/katello.po +247 -262
  404. data/locale/vi/LC_MESSAGES/katello.mo +0 -0
  405. data/locale/vi/katello.po +247 -262
  406. data/locale/vi_VN/LC_MESSAGES/katello.mo +0 -0
  407. data/locale/vi_VN/katello.po +247 -262
  408. data/locale/zh/LC_MESSAGES/katello.mo +0 -0
  409. data/locale/zh/katello.po +247 -262
  410. data/locale/zh_CN/LC_MESSAGES/katello.mo +0 -0
  411. data/locale/zh_CN/katello.po +250 -265
  412. data/locale/zh_TW/LC_MESSAGES/katello.mo +0 -0
  413. data/locale/zh_TW/katello.po +257 -272
  414. data/webpack/ForemanColumnExtensions/index.js +71 -3
  415. data/webpack/ForemanColumnExtensions/index.scss +9 -0
  416. data/webpack/__mocks__/foremanReact/Root/Context/ForemanContext.js +1 -0
  417. data/webpack/components/extensions/HostDetails/ActionsBar/index.js +14 -8
  418. data/webpack/components/extensions/HostDetails/Cards/ErrataOverviewCard.js +1 -1
  419. data/webpack/components/extensions/HostDetails/Cards/SystemPurposeCard/SystemPurposeCard.js +1 -20
  420. data/webpack/components/extensions/HostDetails/Cards/SystemPurposeCard/SystemPurposeEditModal.js +3 -61
  421. data/webpack/components/extensions/HostDetails/Cards/SystemPurposeCard/__tests__/SystemPurposeCard.test.js +0 -5
  422. data/webpack/components/extensions/HostDetails/Cards/SystemPurposeCard/__tests__/SystemPurposeEditModal.test.js +0 -5
  423. data/webpack/components/extensions/HostDetails/DetailsTabCards/ImageModeCard.js +87 -0
  424. data/webpack/components/extensions/HostDetails/DetailsTabCards/RegistrationCard.js +28 -2
  425. data/webpack/components/extensions/HostDetails/Tabs/DebsTab/DebInstallModal.js +1 -1
  426. data/webpack/components/extensions/HostDetails/Tabs/ErrataTab/ErrataTab.js +2 -2
  427. data/webpack/components/extensions/HostDetails/Tabs/PackagesTab/PackageInstallModal.js +1 -1
  428. data/webpack/components/extensions/Hosts/FontAwesomeImageModeIcon.js +55 -0
  429. data/webpack/containers/Application/config.js +5 -0
  430. data/webpack/global_index.js +3 -1
  431. data/webpack/redux/actions/RedHatRepositories/helpers.js +12 -6
  432. data/webpack/scenes/BootedContainerImages/BootedContainerImagesConstants.js +5 -0
  433. data/webpack/scenes/BootedContainerImages/BootedContainerImagesPage.js +244 -0
  434. data/webpack/scenes/BootedContainerImages/__tests__/bootedContainerImages.fixtures.js +42 -0
  435. data/webpack/scenes/BootedContainerImages/__tests__/bootedContainerImagesPage.test.js +233 -0
  436. data/webpack/scenes/BootedContainerImages/index.js +4 -0
  437. data/webpack/scenes/ContentViews/Delete/__tests__/affectedHosts.fixtures.json +1 -2
  438. data/webpack/scenes/ContentViews/Details/Filters/CVErrataDateFilterContent.js +39 -7
  439. data/webpack/scenes/ContentViews/Details/Filters/CVErrataIDFilterContent.js +13 -2
  440. data/webpack/scenes/ContentViews/Details/Filters/CVFilterDetailType.js +1 -1
  441. data/webpack/scenes/ContentViews/Details/Filters/__tests__/cvErrataDateFilterContent.test.js +1 -0
  442. data/webpack/scenes/ContentViews/Details/Repositories/RepoIcon.js +4 -2
  443. data/webpack/scenes/ContentViews/Details/Versions/BulkDelete/__tests__/hosts.fixtures.json +1 -2
  444. data/webpack/scenes/ContentViews/Details/Versions/Delete/RemoveSteps/CVReassignActivationKeysForm.js +20 -1
  445. data/webpack/scenes/ContentViews/Details/Versions/Delete/RemoveSteps/CVReassignHostsForm.js +20 -1
  446. data/webpack/scenes/ContentViews/Details/Versions/Delete/RemoveSteps/CVVersionRemoveReview.js +128 -18
  447. data/webpack/scenes/ContentViews/Details/Versions/Delete/__tests__/cvAffectedActivationKeys.fixture.json +0 -1
  448. data/webpack/scenes/ContentViews/Details/Versions/Delete/__tests__/cvAffectedHosts.fixture.json +1 -2
  449. data/webpack/scenes/ContentViews/Details/Versions/Delete/__tests__/cvVersionRemove.test.js +6 -4
  450. data/webpack/scenes/ContentViews/Details/Versions/Delete/affectedActivationKeys.js +5 -1
  451. data/webpack/scenes/ContentViews/Details/Versions/Delete/affectedHosts.js +6 -1
  452. data/webpack/scenes/ContentViews/__tests__/contentViewPage.test.js +1 -1
  453. data/webpack/scenes/ContentViews/expansions/DetailsExpansion.js +5 -1
  454. data/webpack/scenes/SmartProxy/ExpandableCvDetails.js +4 -2
  455. data/webpack/scenes/SmartProxy/__tests__/SmartProxyContentTest.js +38 -0
  456. data/webpack/scenes/Subscriptions/Details/SubscriptionPurposeAttributes.js +0 -1
  457. data/webpack/scenes/Subscriptions/Details/__tests__/__snapshots__/SubscriptionDetailInfo.test.js.snap +0 -10
  458. data/webpack/scenes/Subscriptions/Details/__tests__/__snapshots__/SubscriptionDetails.test.js.snap +0 -3
  459. data/webpack/scenes/Subscriptions/Details/__tests__/subscriptionDetails.fixtures.js +0 -1
  460. metadata +61 -58
  461. data/app/models/katello/activation_key_purpose_addon.rb +0 -6
  462. data/app/models/katello/purpose_addon.rb +0 -11
  463. data/app/models/katello/subscription_facet_purpose_addon.rb +0 -6
  464. data/lib/monkeys/fx_sqlite_skip.rb +0 -13
  465. data/locale/action_names.rb +0 -181
  466. data/locale/bn/katello.po.time_stamp +0 -0
  467. data/locale/bn_IN/katello.po.time_stamp +0 -0
  468. data/locale/ca/katello.po.time_stamp +0 -0
  469. data/locale/cs/katello.po.time_stamp +0 -0
  470. data/locale/cs_CZ/katello.po.time_stamp +0 -0
  471. data/locale/de/katello.po.time_stamp +0 -0
  472. data/locale/de_AT/katello.po.time_stamp +0 -0
  473. data/locale/de_DE/katello.po.time_stamp +0 -0
  474. data/locale/el/katello.po.time_stamp +0 -0
  475. data/locale/en/katello.po.time_stamp +0 -0
  476. data/locale/en_GB/katello.po.time_stamp +0 -0
  477. data/locale/en_US/katello.po.time_stamp +0 -0
  478. data/locale/es/katello.po.time_stamp +0 -0
  479. data/locale/et_EE/katello.po.time_stamp +0 -0
  480. data/locale/fr/katello.po.time_stamp +0 -0
  481. data/locale/gl/katello.po.time_stamp +0 -0
  482. data/locale/gu/katello.po.time_stamp +0 -0
  483. data/locale/he_IL/katello.po.time_stamp +0 -0
  484. data/locale/hi/katello.po.time_stamp +0 -0
  485. data/locale/id/katello.po.time_stamp +0 -0
  486. data/locale/it/katello.po.time_stamp +0 -0
  487. data/locale/ja/katello.po.time_stamp +0 -0
  488. data/locale/ka/katello.po.time_stamp +0 -0
  489. data/locale/kn/katello.po.time_stamp +0 -0
  490. data/locale/ko/katello.po.time_stamp +0 -0
  491. data/locale/ml_IN/katello.po.time_stamp +0 -0
  492. data/locale/mr/katello.po.time_stamp +0 -0
  493. data/locale/nl_NL/katello.po.time_stamp +0 -0
  494. data/locale/or/katello.po.time_stamp +0 -0
  495. data/locale/pa/katello.po.time_stamp +0 -0
  496. data/locale/pl/katello.po.time_stamp +0 -0
  497. data/locale/pl_PL/katello.po.time_stamp +0 -0
  498. data/locale/pt/katello.po.time_stamp +0 -0
  499. data/locale/pt_BR/katello.po.time_stamp +0 -0
  500. data/locale/ro/katello.po.time_stamp +0 -0
  501. data/locale/ro_RO/katello.po.time_stamp +0 -0
  502. data/locale/ru/katello.po.time_stamp +0 -0
  503. data/locale/sl/katello.po.time_stamp +0 -0
  504. data/locale/sv_SE/katello.po.time_stamp +0 -0
  505. data/locale/ta/katello.po.time_stamp +0 -0
  506. data/locale/ta_IN/katello.po.time_stamp +0 -0
  507. data/locale/te/katello.po.time_stamp +0 -0
  508. data/locale/tr/katello.po.time_stamp +0 -0
  509. data/locale/vi/katello.po.time_stamp +0 -0
  510. data/locale/vi_VN/katello.po.time_stamp +0 -0
  511. data/locale/zh/katello.po.time_stamp +0 -0
  512. data/locale/zh_CN/katello.po.time_stamp +0 -0
  513. data/locale/zh_TW/katello.po.time_stamp +0 -0
@@ -46,7 +46,12 @@ const CVErrataDateFilterContent = ({
46
46
  selectCVFilterDetails(state, cvId, filterId), shallowEqual);
47
47
  const { repositories = [], rules } = filterDetails;
48
48
  const [{
49
- id, types, start_date: ruleStartDate, end_date: ruleEndDate, date_type: ruleDateType,
49
+ id,
50
+ types,
51
+ allow_other_types: ruleAllowOtherTypes,
52
+ start_date: ruleStartDate,
53
+ end_date: ruleEndDate,
54
+ date_type: ruleDateType,
50
55
  } = {}] = rules;
51
56
  const { permissions } = details;
52
57
  const [startDate, setStartDate] = useState(convertAPIDateToUIFormat(ruleStartDate));
@@ -54,12 +59,23 @@ const CVErrataDateFilterContent = ({
54
59
  const [dateType, setDateType] = useState(ruleDateType);
55
60
  const [dateTypeSelectOpen, setDateTypeSelectOpen] = useState(false);
56
61
  const [typeSelectOpen, setTypeSelectOpen] = useState(false);
57
- const [selectedTypes, setSelectedTypes] = useState(types);
58
62
  const dispatch = useDispatch();
59
63
  const [activeTabKey, setActiveTabKey] = useState(0);
60
64
  const [startEntry, setStartEntry] = useState(false);
61
65
  const [endEntry, setEndEntry] = useState(false);
62
66
 
67
+ const getInitialSelectedTypes = () => {
68
+ if (!types) {
69
+ return ['other'];
70
+ }
71
+ if (ruleAllowOtherTypes) {
72
+ return [...types, 'other'];
73
+ }
74
+ return types;
75
+ };
76
+
77
+ const [selectedTypes, setSelectedTypes] = useState(getInitialSelectedTypes());
78
+
63
79
  const onSave = () => {
64
80
  dispatch(editCVFilterRule(
65
81
  filterId,
@@ -68,8 +84,9 @@ const CVErrataDateFilterContent = ({
68
84
  content_view_filter_id: filterId,
69
85
  start_date: startDate && startDate !== '' ? dateParse(startDate) : null,
70
86
  end_date: endDate && endDate !== '' ? dateParse(endDate) : null,
71
- types: selectedTypes,
87
+ types: selectedTypes.filter(e => e !== 'other'),
72
88
  date_type: dateType,
89
+ allow_other_types: selectedTypes.includes('other'),
73
90
  },
74
91
  () => {
75
92
  dispatch({ type: CONTENT_VIEW_NEEDS_PUBLISH });
@@ -81,15 +98,21 @@ const CVErrataDateFilterContent = ({
81
98
  const resetFilters = () => {
82
99
  setStartDate(convertAPIDateToUIFormat(ruleStartDate));
83
100
  setEndDate(convertAPIDateToUIFormat(ruleEndDate));
84
- setSelectedTypes(types);
85
101
  setDateType(ruleDateType);
102
+ setSelectedTypes(getInitialSelectedTypes());
86
103
  };
87
104
 
88
105
  const onTypeSelect = (selection) => {
89
106
  if (selectedTypes.includes(selection)) {
107
+ // If the selection is the only selection remaining, do not allow it to be removed
90
108
  if (selectedTypes.length === 1) return;
109
+
110
+ // Filter out the current selection to deselect it
91
111
  setSelectedTypes(selectedTypes.filter(e => e !== selection));
92
- } else setSelectedTypes([...selectedTypes, selection]);
112
+ } else {
113
+ // Add the selection to the selected types
114
+ setSelectedTypes([...selectedTypes, selection]);
115
+ }
93
116
  };
94
117
 
95
118
  const singleSelection = selection => (selectedTypes.length === 1
@@ -99,7 +122,7 @@ const CVErrataDateFilterContent = ({
99
122
  (
100
123
  isEqual(convertAPIDateToUIFormat(ruleStartDate), startDate) &&
101
124
  isEqual(convertAPIDateToUIFormat(ruleEndDate), endDate) &&
102
- isEqual(sortBy(types), sortBy(selectedTypes)) &&
125
+ isEqual(sortBy(getInitialSelectedTypes()), sortBy(selectedTypes)) &&
103
126
  isEqual(ruleDateType, dateType)
104
127
  );
105
128
 
@@ -171,6 +194,15 @@ const CVErrataDateFilterContent = ({
171
194
  {__('Bugfix')}
172
195
  </p>
173
196
  </SelectOption>
197
+ <SelectOption
198
+ isDisabled={singleSelection('other') || !hasPermission(permissions, 'edit_content_views')}
199
+ key="other"
200
+ value="other"
201
+ >
202
+ <p style={{ marginTop: '4px' }}>
203
+ {__('Other')}
204
+ </p>
205
+ </SelectOption>
174
206
  </Select>
175
207
  </FlexItem>
176
208
  <FlexItem span={1} spacer={{ default: 'spacerNone' }}>
@@ -178,7 +210,7 @@ const CVErrataDateFilterContent = ({
178
210
  <Tooltip
179
211
  position="top"
180
212
  content={
181
- __('Atleast one errata type needs to be selected.')
213
+ __('At least one errata type option needs to be selected.')
182
214
  }
183
215
  >
184
216
  <OutlinedQuestionCircleIcon />
@@ -60,7 +60,7 @@ const CVErrataIDFilterContent = ({
60
60
  const hasNotAddedSelected = rows.some(({ selected, added }) => selected && !added);
61
61
  const [statusSelected, setStatusSelected] = useState(ALL_STATUSES);
62
62
  const [typeSelectOpen, setTypeSelectOpen] = useState(false);
63
- const [selectedTypes, setSelectedTypes] = useState(ERRATA_TYPES);
63
+ const [selectedTypes, setSelectedTypes] = useState([...ERRATA_TYPES, 'other']);
64
64
  const [startDate, setStartDate] = useState('');
65
65
  const [endDate, setEndDate] = useState('');
66
66
  const activeFilters = [statusSelected, selectedTypes, startDate, endDate];
@@ -198,9 +198,15 @@ const CVErrataIDFilterContent = ({
198
198
 
199
199
  const onTypeSelect = (selection) => {
200
200
  if (selectedTypes.includes(selection)) {
201
+ // If the selection is the only selection remaining, do not allow it to be removed
201
202
  if (selectedTypes.length === 1) return;
203
+
204
+ // Filter out the current selection to deselect it
202
205
  setSelectedTypes(selectedTypes.filter(e => e !== selection));
203
- } else setSelectedTypes([...selectedTypes, selection]);
206
+ } else {
207
+ // Add the current selection to the selected types
208
+ setSelectedTypes([...selectedTypes, selection]);
209
+ }
204
210
  setTypeSelectOpen(false);
205
211
  };
206
212
 
@@ -326,6 +332,11 @@ const CVErrataIDFilterContent = ({
326
332
  {__('Bugfix')}
327
333
  </p>
328
334
  </SelectOption>
335
+ <SelectOption isDisabled={singleSelection('bugfix')} key="other" value="other">
336
+ <p style={{ marginTop: '4px' }}>
337
+ {__('Other')}
338
+ </p>
339
+ </SelectOption>
329
340
  </Select>
330
341
  </SplitItem>
331
342
  {hasPermission(permissions, 'edit_content_views') &&
@@ -47,7 +47,7 @@ const CVFilterDetailType = ({
47
47
  details={details}
48
48
  />);
49
49
  case 'erratum':
50
- if (head(rules)?.types) {
50
+ if (head(rules)?.types || head(rules)?.allow_other_types) {
51
51
  return (<CVErrataDateFilterContent
52
52
  cvId={cvId}
53
53
  filterId={filterId}
@@ -23,6 +23,7 @@ test('Can display errata-date filter rule and edit', async (done) => {
23
23
  end_date: '2020-08-15T12:00:00.000Z',
24
24
  types: ['enhancement', 'security'],
25
25
  date_type: 'issued',
26
+ allow_other_types: false,
26
27
  };
27
28
 
28
29
  const ruleEditScope = nockInstance
@@ -3,7 +3,7 @@ import { Tooltip } from '@patternfly/react-core';
3
3
  import { BundleIcon, MiddlewareIcon, BoxIcon, CodeBranchIcon, FanIcon, TenantIcon, AnsibleTowerIcon } from '@patternfly/react-icons';
4
4
  import PropTypes from 'prop-types';
5
5
 
6
- const RepoIcon = ({ type }) => {
6
+ const RepoIcon = ({ type, customTooltip }) => {
7
7
  const iconMap = {
8
8
  yum: BundleIcon,
9
9
  docker: MiddlewareIcon,
@@ -14,15 +14,17 @@ const RepoIcon = ({ type }) => {
14
14
  };
15
15
  const Icon = iconMap[type] || BoxIcon;
16
16
 
17
- return <Tooltip content={<div>{type}</div>}><Icon aria-label={`${type}_type_icon`} /></Tooltip>;
17
+ return <Tooltip content={<div>{customTooltip ?? type}</div>}><Icon aria-label={`${type}_type_icon`} /></Tooltip>;
18
18
  };
19
19
 
20
20
  RepoIcon.propTypes = {
21
21
  type: PropTypes.string,
22
+ customTooltip: PropTypes.string,
22
23
  };
23
24
 
24
25
  RepoIcon.defaultProps = {
25
26
  type: '', // prevent errors if data isn't loaded yet
27
+ customTooltip: null,
26
28
  };
27
29
 
28
30
  export default RepoIcon;
@@ -138,8 +138,7 @@
138
138
  "purpose_role": "",
139
139
  "purpose_usage": "",
140
140
  "hypervisor": false,
141
- "user": null,
142
- "purpose_addons": []
141
+ "user": null
143
142
  },
144
143
  "infrastructure_facet": {
145
144
  "foreman_instance": false,
@@ -1,12 +1,13 @@
1
1
  import React, { useState, useContext } from 'react';
2
2
  import { useDispatch, useSelector } from 'react-redux';
3
3
  import useDeepCompareEffect from 'use-deep-compare-effect';
4
- import { ExpandableSection, SelectOption } from '@patternfly/react-core';
4
+ import { ExpandableSection, SelectOption, Alert, AlertActionCloseButton } from '@patternfly/react-core';
5
5
  import { STATUS } from 'foremanReact/constants';
6
6
  import { translate as __ } from 'foremanReact/common/I18n';
7
7
  import EnvironmentPaths from '../../../../components/EnvironmentPaths/EnvironmentPaths';
8
8
  import getContentViews from '../../../../ContentViewsActions';
9
9
  import { selectContentViewError, selectContentViews, selectContentViewStatus } from '../../../../ContentViewSelectors';
10
+ import { selectCVActivationKeys } from '../../../ContentViewDetailSelectors';
10
11
  import AffectedActivationKeys from '../affectedActivationKeys';
11
12
  import DeleteContext from '../DeleteContext';
12
13
  import ContentViewSelect from '../../../../components/ContentViewSelect/ContentViewSelect';
@@ -17,7 +18,9 @@ const CVReassignActivationKeysForm = () => {
17
18
  const contentViewsInEnvResponse = useSelector(selectContentViews);
18
19
  const contentViewsInEnvStatus = useSelector(selectContentViewStatus);
19
20
  const contentViewsInEnvError = useSelector(selectContentViewError);
21
+ const activationKeysResponse = useSelector(selectCVActivationKeys);
20
22
  const cvInEnvLoading = contentViewsInEnvStatus === STATUS.PENDING;
23
+ const [alertDismissed, setAlertDismissed] = useState(false);
21
24
  const [cvSelectOpen, setCVSelectOpen] = useState(false);
22
25
  const [cvSelectOptions, setCvSelectionOptions] = useState([]);
23
26
  const [showActivationKeys, setShowActivationKeys] = useState(false);
@@ -72,6 +75,9 @@ const CVReassignActivationKeysForm = () => {
72
75
  contentViewsInEnvError, selectedEnvForAK, setSelectedCVForAK, setSelectedCVNameForAK,
73
76
  cvInEnvLoading, selectedCVForAK, cvId, versionEnvironments, selectedEnvSet]);
74
77
 
78
+ const multiCVWarning = activationKeysResponse?.results?.some?.(key =>
79
+ key.multi_content_view_environment);
80
+
75
81
  const fetchSelectedCVName = (id) => {
76
82
  const { results } = contentViewsInEnvResponse ?? { };
77
83
  return results.filter(cv => cv.id === id)[0]?.name;
@@ -102,8 +108,21 @@ const CVReassignActivationKeysForm = () => {
102
108
  cvSelectOptions,
103
109
  });
104
110
 
111
+ const multiCVRemovalInfo = __('This environment is used in one or more multi-environment activation keys. The environment will simply be removed from the multi-environment keys. The content view and lifecycle environment you select here will only apply to single-environment activation keys. See hammer activation-key --help for more details.');
112
+
105
113
  return (
106
114
  <>
115
+ {!alertDismissed && multiCVWarning && (
116
+ <Alert
117
+ ouiaId="multi-cv-warning-alert"
118
+ variant="warning"
119
+ isInline
120
+ title={__('Warning')}
121
+ actionClose={<AlertActionCloseButton onClose={() => setAlertDismissed(true)} />}
122
+ >
123
+ <p>{multiCVRemovalInfo}</p>
124
+ </Alert>
125
+ )}
107
126
  <EnvironmentPaths
108
127
  userCheckedItems={selectedEnvForAK}
109
128
  setUserCheckedItems={setSelectedEnvForAK}
@@ -1,12 +1,13 @@
1
1
  import React, { useState, useContext } from 'react';
2
2
  import { useDispatch, useSelector } from 'react-redux';
3
3
  import useDeepCompareEffect from 'use-deep-compare-effect';
4
- import { ExpandableSection, SelectOption } from '@patternfly/react-core';
4
+ import { ExpandableSection, SelectOption, Alert, AlertActionCloseButton } from '@patternfly/react-core';
5
5
  import { STATUS } from 'foremanReact/constants';
6
6
  import { translate as __ } from 'foremanReact/common/I18n';
7
7
  import EnvironmentPaths from '../../../../components/EnvironmentPaths/EnvironmentPaths';
8
8
  import getContentViews from '../../../../ContentViewsActions';
9
9
  import { selectContentViewError, selectContentViews, selectContentViewStatus } from '../../../../ContentViewSelectors';
10
+ import { selectCVHosts } from '../../../ContentViewDetailSelectors';
10
11
  import AffectedHosts from '../affectedHosts';
11
12
  import DeleteContext from '../DeleteContext';
12
13
  import ContentViewSelect from '../../../../components/ContentViewSelect/ContentViewSelect';
@@ -25,6 +26,13 @@ const CVReassignHostsForm = () => {
25
26
  cvId, versionEnvironments, selectedEnvSet, selectedEnvForHost, setSelectedEnvForHost,
26
27
  currentStep, selectedCVForHosts, setSelectedCVNameForHosts, setSelectedCVForHosts,
27
28
  } = useContext(DeleteContext);
29
+ const [alertDismissed, setAlertDismissed] = useState(false);
30
+ const hostResponse = useSelector(selectCVHosts);
31
+
32
+ const multiCVWarning = hostResponse?.results?.some?.(host =>
33
+ host.content_facet_attributes?.multi_content_view_environment);
34
+
35
+ const multiCVRemovalInfo = __('This content view version is used in one or more multi-environment hosts. The version will simply be removed from the multi-environment hosts. The content view and lifecycle environment you select here will only apply to single-environment hosts. See hammer activation-key --help for more details.');
28
36
 
29
37
  // Fetch content views for selected environment to reassign hosts to.
30
38
  useDeepCompareEffect(
@@ -103,6 +111,17 @@ const CVReassignHostsForm = () => {
103
111
 
104
112
  return (
105
113
  <>
114
+ {!alertDismissed && multiCVWarning && (
115
+ <Alert
116
+ ouiaId="multi-cv-warning-alert"
117
+ variant="warning"
118
+ isInline
119
+ title={__('Warning')}
120
+ actionClose={<AlertActionCloseButton onClose={() => setAlertDismissed(true)} />}
121
+ >
122
+ <p>{multiCVRemovalInfo}</p>
123
+ </Alert>
124
+ )}
106
125
  <EnvironmentPaths
107
126
  userCheckedItems={selectedEnvForHost}
108
127
  setUserCheckedItems={setSelectedEnvForHost}
@@ -2,28 +2,44 @@ import React, { useContext, useState } from 'react';
2
2
  import { useSelector } from 'react-redux';
3
3
  import { Alert, Flex, FlexItem, Label, AlertActionCloseButton } from '@patternfly/react-core';
4
4
  import { ExclamationTriangleIcon } from '@patternfly/react-icons';
5
+ import { FormattedMessage } from 'react-intl';
5
6
  import { translate as __ } from 'foremanReact/common/I18n';
6
- import { selectCVActivationKeys, selectCVHosts } from '../../../ContentViewDetailSelectors';
7
+ import { selectCVActivationKeys, selectCVHosts, selectCVVersions } from '../../../ContentViewDetailSelectors';
7
8
  import DeleteContext from '../DeleteContext';
8
- import { pluralize } from '../../../../../../utils/helpers';
9
9
  import WizardHeader from '../../../../components/WizardHeader';
10
10
 
11
11
  const CVVersionRemoveReview = () => {
12
12
  const [alertDismissed, setAlertDismissed] = useState(false);
13
13
  const {
14
- cvId, versionNameToRemove, versionEnvironments, selectedEnvSet,
14
+ cvId, versionIdToRemove, versionNameToRemove, selectedEnvSet,
15
15
  selectedEnvForAK, selectedCVNameForAK, selectedCVNameForHosts,
16
16
  selectedEnvForHost, affectedActivationKeys, affectedHosts, deleteFlow, removeDeletionFlow,
17
17
  } = useContext(DeleteContext);
18
18
  const activationKeysResponse = useSelector(state => selectCVActivationKeys(state, cvId));
19
19
  const hostsResponse = useSelector(state => selectCVHosts(state, cvId));
20
- const { results: hostResponse } = hostsResponse;
21
- const { results: akResponse } = activationKeysResponse;
22
- const selectedEnv = versionEnvironments.filter(env => selectedEnvSet.has(env.id));
20
+ const { results: hostResponse = [] } = hostsResponse || {};
21
+ const { results: akResponse = [] } = activationKeysResponse || {};
22
+ const cvVersions = useSelector(state => selectCVVersions(state, cvId));
23
23
  const versionDeleteInfo = __(`Version ${versionNameToRemove} will be deleted from all environments. It will no longer be available for promotion.`);
24
24
  const removalNotice = __(`Version ${versionNameToRemove} will be removed from the environments listed below, and will remain available for later promotion. ` +
25
25
  'Changes listed below will be effective after clicking Remove.');
26
26
 
27
+ const matchedCVResults = cvVersions?.results?.filter(cv => cv.id === versionIdToRemove) || [];
28
+ const selectedCVE = matchedCVResults
29
+ .flatMap(cv => cv.content_view_environments || [])
30
+ .filter(env => selectedEnvSet.has(env.environment_id));
31
+
32
+ const multiCVHosts = hostResponse?.filter(host =>
33
+ host.content_facet_attributes?.multi_content_view_environment) || [];
34
+ const multiCVHostsCount = multiCVHosts.length;
35
+
36
+ const singleCVHostsCount = (hostResponse?.length || 0) - multiCVHostsCount;
37
+
38
+ const multiCVActivationKeys = akResponse.filter(key => key.multi_content_view_environment);
39
+ const multiCVActivationKeysCount = multiCVActivationKeys.length;
40
+
41
+ const singleCVActivationKeysCount = akResponse.length - multiCVActivationKeysCount;
42
+
27
43
  return (
28
44
  <>
29
45
  <WizardHeader title={__('Review details')} />
@@ -38,7 +54,7 @@ const CVVersionRemoveReview = () => {
38
54
  <p style={{ marginBottom: '0.5em' }}>{versionDeleteInfo}</p>
39
55
  </Alert>}
40
56
  {!(deleteFlow || removeDeletionFlow) && <WizardHeader description={removalNotice} />}
41
- {(selectedEnv.length !== 0) &&
57
+ {(selectedCVE?.length !== 0) &&
42
58
  <>
43
59
  <h3>{__('Environments')}</h3>
44
60
  <Flex>
@@ -46,27 +62,121 @@ const CVVersionRemoveReview = () => {
46
62
  <FlexItem style={{ marginBottom: '0.5em' }}>{__('This version will be removed from:')}</FlexItem>
47
63
  </Flex>
48
64
  <Flex>
49
- {selectedEnv?.map(({ name, id }) =>
65
+ {selectedCVE?.map(({ environment_name: name, environment_id: id }) =>
50
66
  <FlexItem key={name}><Label isTruncated color="purple" href={`/lifecycle_environments/${id}`}>{name}</Label></FlexItem>)}
51
67
  </Flex>
52
68
  </>}
53
69
  {affectedHosts &&
54
70
  <>
55
71
  <h3>{__('Content hosts')}</h3>
56
- <Flex>
57
- <FlexItem><ExclamationTriangleIcon /></FlexItem>
58
- <FlexItem><p>{__(`${pluralize(hostResponse.length, 'host')} will be moved to content view ${selectedCVNameForHosts} in `)}</p></FlexItem>
59
- <FlexItem><Label isTruncated color="purple" href={`/lifecycle_environments/${selectedEnvForHost[0].id}`}>{selectedEnvForHost[0].name}</Label></FlexItem>
60
- </Flex>
72
+ {singleCVHostsCount > 0 && (
73
+ <Flex>
74
+ <FlexItem><ExclamationTriangleIcon /></FlexItem>
75
+ <FlexItem data-testid="single-cv-hosts-remove">
76
+ <FormattedMessage
77
+ id="single-cv-hosts-remove"
78
+ defaultMessage="{count, plural, one {# {singular}} other {# {plural}}} will be moved to content view {cvName} in {envName}."
79
+ values={{
80
+ count: singleCVHostsCount,
81
+ singular: __('host'),
82
+ plural: __('hosts'),
83
+ cvName: selectedCVNameForHosts,
84
+ envName: selectedEnvForHost[0] && (
85
+ <Label isTruncated color="purple" href={`/lifecycle_environments/${selectedEnvForHost[0].id}`}>
86
+ {selectedEnvForHost[0].name}
87
+ </Label>
88
+ ),
89
+ }}
90
+ />
91
+ </FlexItem>
92
+ </Flex>
93
+ )}
94
+ {multiCVHostsCount > 0 && (
95
+ <Flex>
96
+ <FlexItem><ExclamationTriangleIcon /></FlexItem>
97
+ <FlexItem>
98
+ <FormattedMessage
99
+ id="multi-cv-hosts-remove"
100
+ defaultMessage="{envSingularOrPlural} {envCV} will be removed from {hostCount, plural, one {# {hostSingular}} other {# {hostPlural}}}."
101
+ values={{
102
+ envSingularOrPlural: (
103
+ <FormattedMessage
104
+ id="environment.plural"
105
+ defaultMessage="{count, plural, one {{envSingular}} other {{envPlural}}}"
106
+ values={{
107
+ count: selectedCVE?.length,
108
+ envSingular: __('Content view environment'),
109
+ envPlural: __('Content view environments'),
110
+ }}
111
+ />
112
+ ),
113
+ envCV: selectedCVE
114
+ ?.map(cve => cve.label)
115
+ .join(', '),
116
+ hostCount: multiCVHostsCount,
117
+ hostSingular: __('multi-environment host'),
118
+ hostPlural: __('multi-environment hosts'),
119
+ }}
120
+ />
121
+ </FlexItem>
122
+ </Flex>
123
+ )}
61
124
  </>}
62
125
  {affectedActivationKeys &&
63
126
  <>
64
127
  <h3>{__('Activation keys')}</h3>
65
- <Flex>
66
- <FlexItem><ExclamationTriangleIcon /></FlexItem>
67
- <FlexItem><p>{__(`${pluralize(akResponse.length, 'activation key')} will be moved to content view ${selectedCVNameForAK} in `)}</p></FlexItem>
68
- <FlexItem><Label isTruncated color="purple" href={`/lifecycle_environments/${selectedEnvForAK[0].id}`}>{selectedEnvForAK[0].name}</Label></FlexItem>
69
- </Flex>
128
+ {singleCVActivationKeysCount > 0 && (
129
+ <Flex>
130
+ <FlexItem><ExclamationTriangleIcon /></FlexItem>
131
+ <FlexItem data-testid="single-cv-activation-keys-remove">
132
+ <FormattedMessage
133
+ id="single-cv-activation-keys-remove"
134
+ defaultMessage="{count, plural, one {# {singular}} other {# {plural}}} will be moved to content view {cvName} in {envName}."
135
+ values={{
136
+ count: singleCVActivationKeysCount,
137
+ singular: __('activation key'),
138
+ plural: __('activation keys'),
139
+ cvName: selectedCVNameForAK,
140
+ envName: selectedEnvForAK[0] && (
141
+ <Label isTruncated color="purple" href={`/lifecycle_environments/${selectedEnvForAK[0].id}`}>
142
+ {selectedEnvForAK[0].name}
143
+ </Label>
144
+ ),
145
+ }}
146
+ />
147
+ </FlexItem>
148
+ </Flex>
149
+ )}
150
+ {multiCVActivationKeysCount > 0 && (
151
+ <Flex>
152
+ <FlexItem><ExclamationTriangleIcon /></FlexItem>
153
+ <FlexItem>
154
+ <FormattedMessage
155
+ id="multi-cv-activation-keys-remove"
156
+ defaultMessage="{envSingularOrPlural} {envCV} will be removed from {akCount, plural, one {# {keySingular}} other {# {keyPlural}}}."
157
+ values={{
158
+ envSingularOrPlural: (
159
+ <FormattedMessage
160
+ id="environment.plural"
161
+ defaultMessage="{count, plural, one {{envSingular}} other {{envPlural}}}"
162
+ values={{
163
+ count: selectedCVE?.length,
164
+ envSingular: __('Content view environment'),
165
+ envPlural: __('Content view environments'),
166
+ }}
167
+ />
168
+ ),
169
+ envCV: selectedCVE
170
+ ?.map(cve => cve.label)
171
+ .join(', '),
172
+ akCount: multiCVActivationKeysCount,
173
+ keySingular: __('multi-environment activation key'),
174
+ keyPlural: __('multi-environment activation keys'),
175
+ }}
176
+ />
177
+ </FlexItem>
178
+ </Flex>
179
+ )}
70
180
  </>}
71
181
  </>
72
182
  );
@@ -42,7 +42,6 @@
42
42
  },
43
43
  "products": [],
44
44
  "host_collections": [],
45
- "purpose_addons": [],
46
45
  "permissions": {
47
46
  "view_activation_keys": true,
48
47
  "edit_activation_keys": true,
@@ -132,8 +132,7 @@
132
132
  "purpose_role": "",
133
133
  "purpose_usage": "",
134
134
  "hypervisor": false,
135
- "user": null,
136
- "purpose_addons": []
135
+ "user": null
137
136
  }
138
137
  }
139
138
  ]
@@ -152,7 +152,8 @@ test('Can open Remove wizard and remove version from environment with hosts', as
152
152
 
153
153
 
154
154
  const {
155
- getByText, getAllByText, getByLabelText, getAllByLabelText, queryByText, getByPlaceholderText,
155
+ getByText, getAllByText, getByLabelText, getAllByLabelText, queryByText,
156
+ getByPlaceholderText, getByTestId,
156
157
  } = renderWithRedux(
157
158
  <ContentViewVersions cvId={2} details={cvDetailData} />,
158
159
  renderOptions,
@@ -192,7 +193,7 @@ test('Can open Remove wizard and remove version from environment with hosts', as
192
193
  fireEvent.click(getByText('Next'));
193
194
  await patientlyWaitFor(() => {
194
195
  expect(getByText('Review details')).toBeInTheDocument();
195
- expect(getByText('1 host will be moved to content view cv2 in')).toBeInTheDocument();
196
+ expect(getByTestId('single-cv-hosts-remove')).toBeInTheDocument();
196
197
  });
197
198
  fireEvent.click(getAllByText('Remove')[0]);
198
199
  assertNockRequest(scope);
@@ -238,7 +239,8 @@ test('Can open Remove wizard and remove version from environment with activation
238
239
 
239
240
 
240
241
  const {
241
- getByText, getAllByText, getByLabelText, getAllByLabelText, queryByText, getByPlaceholderText,
242
+ getByText, getAllByText, getByLabelText, getAllByLabelText, queryByText,
243
+ getByPlaceholderText, getByTestId,
242
244
  } = renderWithRedux(
243
245
  <ContentViewVersions cvId={2} details={cvDetailData} />,
244
246
  renderOptions,
@@ -278,7 +280,7 @@ test('Can open Remove wizard and remove version from environment with activation
278
280
  fireEvent.click(getByText('Next'));
279
281
  await patientlyWaitFor(() => {
280
282
  expect(getByText('Review details')).toBeInTheDocument();
281
- expect(getByText('1 activation key will be moved to content view cv2 in')).toBeInTheDocument();
283
+ expect(getByTestId('single-cv-activation-keys-remove')).toBeInTheDocument();
282
284
  });
283
285
  fireEvent.click(getAllByText('Remove')[0]);
284
286
 
@@ -35,6 +35,7 @@ const AffectedActivationKeys = ({
35
35
  const columnHeaders = [
36
36
  __('Name'),
37
37
  __('Environment'),
38
+ __('Multi Content View Environment'),
38
39
  ];
39
40
  const emptyContentTitle = __('No matching activation keys found.');
40
41
  const emptyContentBody = __("Given criteria doesn't match any activation keys. Try changing your rule.");
@@ -65,12 +66,15 @@ const AffectedActivationKeys = ({
65
66
  </Tr>
66
67
  </Thead>
67
68
  <Tbody>
68
- {results?.map(({ name, id, environment }) => (
69
+ {results?.map(({
70
+ name, id, environment, multi_content_view_environment: multiContentViewEnvironment,
71
+ }) => (
69
72
  <Tr ouiaId={id} key={id}>
70
73
  <Td>
71
74
  <a rel="noreferrer" target="_blank" href={urlBuilder(`activation_keys/${id}`, '')}>{name}</a>
72
75
  </Td>
73
76
  <Td><EnvironmentLabels environments={environment} /></Td>
77
+ <Td>{ multiContentViewEnvironment ? 'Yes' : 'No' }</Td>
74
78
  </Tr>
75
79
  ))
76
80
  }
@@ -30,6 +30,7 @@ const AffectedHosts = ({
30
30
  const columnHeaders = [
31
31
  __('Name'),
32
32
  __('Environment'),
33
+ __('Multi Content View Environment'),
33
34
  ];
34
35
  const emptyContentTitle = __('No matching hosts found.');
35
36
  const emptyContentBody = __("Given criteria doesn't match any hosts. Try changing your rule.");
@@ -63,13 +64,17 @@ const AffectedHosts = ({
63
64
  {results?.map(({
64
65
  name,
65
66
  id,
66
- content_facet_attributes: { lifecycle_environment: environment },
67
+ content_facet_attributes: {
68
+ lifecycle_environment: environment,
69
+ multi_content_view_environment: multiContentViewEnvironment,
70
+ },
67
71
  }) => (
68
72
  <Tr ouiaId={id} key={id}>
69
73
  <Td>
70
74
  <a rel="noreferrer" target="_blank" href={urlBuilder(`new/hosts/${id}`, '')}>{name}</a>
71
75
  </Td>
72
76
  <Td><EnvironmentLabels environments={environment} /></Td>
77
+ <Td>{ multiContentViewEnvironment ? __('Yes') : __('No') }</Td>
73
78
  </Tr>
74
79
  ))
75
80
  }
@@ -132,7 +132,7 @@ test('Can expand cv and show activation keys and hosts', async (done) => {
132
132
  expect(queryByLabelText('activation_keys_link_2').textContent).toEqual('1');
133
133
 
134
134
  // Displays hosts link with count
135
- expect(queryByLabelText('host_link_2')).toHaveAttribute('href', '/hosts?search=content_view_id+%3D+2');
135
+ expect(queryByLabelText('host_link_2')).toHaveAttribute('href', '/new/hosts?search=content_view_id%3D2');
136
136
  expect(queryByLabelText('host_link_2').textContent).toEqual('1');
137
137
  });
138
138
 
@@ -1,6 +1,7 @@
1
1
  import React from 'react';
2
2
  import PropTypes from 'prop-types';
3
3
  import { translate as __ } from 'foremanReact/common/I18n';
4
+ import { useForemanHostsPageUrl } from 'foremanReact/Root/Context/ForemanContext';
4
5
  import RelatedCompositeContentViewsModal from './RelatedCompositeContentViewsModal';
5
6
  import RelatedContentViewComponentsModal from './RelatedContentViewComponentsModal';
6
7
 
@@ -10,6 +11,9 @@ const DetailsExpansion = ({
10
11
  const activationKeyCount = activationKeys.length;
11
12
  const hostCount = hosts.length;
12
13
 
14
+ const baseHostsPageUrl = useForemanHostsPageUrl();
15
+ const hostsPageUrl = `${baseHostsPageUrl}?search=${encodeURIComponent(`content_view_id=${cvId}`)}`;
16
+
13
17
  const relatedContentViewModal = () => {
14
18
  if (cvComposite) {
15
19
  return (
@@ -36,7 +40,7 @@ const DetailsExpansion = ({
36
40
  <div id={`cv-details-expansion-${cvId}`}>
37
41
  {__('Activation keys: ')}<a aria-label={`activation_keys_link_${cvId}`} href={`/activation_keys?search=content_view_id+%3D+${cvId}`}>{activationKeyCount}</a>
38
42
  <br />
39
- {__('Hosts: ')}<a aria-label={`host_link_${cvId}`} href={`/hosts?search=content_view_id+%3D+${cvId}`}>{hostCount}</a>
43
+ {__('Hosts: ')}<a aria-label={`host_link_${cvId}`} href={hostsPageUrl}>{hostCount}</a>
40
44
  <br />
41
45
  {relatedContentViewModal()}
42
46
  </div>