katello 4.4.0.2 → 4.5.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.
Files changed (502) hide show
  1. checksums.yaml +4 -4
  2. data/app/assets/javascripts/katello/hosts/activation_key_edit.js +9 -2
  3. data/app/controllers/katello/api/registry/registry_proxies_controller.rb +3 -0
  4. data/app/controllers/katello/api/rhsm/candlepin_proxies_controller.rb +5 -1
  5. data/app/controllers/katello/api/v2/alternate_content_sources_bulk_actions_controller.rb +44 -0
  6. data/app/controllers/katello/api/v2/alternate_content_sources_controller.rb +121 -0
  7. data/app/controllers/katello/api/v2/content_export_incrementals_controller.rb +39 -3
  8. data/app/controllers/katello/api/v2/content_exports_controller.rb +19 -0
  9. data/app/controllers/katello/api/v2/content_imports_controller.rb +13 -16
  10. data/app/controllers/katello/api/v2/content_view_components_controller.rb +1 -1
  11. data/app/controllers/katello/api/v2/content_view_repositories_controller.rb +1 -1
  12. data/app/controllers/katello/api/v2/content_view_versions_controller.rb +0 -12
  13. data/app/controllers/katello/api/v2/content_views_controller.rb +13 -0
  14. data/app/controllers/katello/api/v2/environments_controller.rb +1 -1
  15. data/app/controllers/katello/api/v2/errata_controller.rb +3 -1
  16. data/app/controllers/katello/api/v2/host_module_streams_controller.rb +8 -2
  17. data/app/controllers/katello/api/v2/host_subscriptions_controller.rb +25 -3
  18. data/app/controllers/katello/api/v2/module_streams_controller.rb +3 -1
  19. data/app/controllers/katello/api/v2/organizations_controller.rb +4 -2
  20. data/app/controllers/katello/api/v2/package_groups_controller.rb +3 -1
  21. data/app/controllers/katello/api/v2/repositories_bulk_actions_controller.rb +1 -1
  22. data/app/controllers/katello/api/v2/repositories_controller.rb +1 -1
  23. data/app/controllers/katello/api/v2/repository_sets_controller.rb +40 -7
  24. data/app/controllers/katello/api/v2/subscriptions_controller.rb +2 -2
  25. data/app/controllers/katello/concerns/api/v2/hosts_controller_extensions.rb +1 -1
  26. data/app/helpers/katello/concerns/smart_proxy_helper_extensions.rb +4 -0
  27. data/app/helpers/katello/hosts_and_hostgroups_helper.rb +21 -3
  28. data/app/lib/actions/katello/alternate_content_source/create.rb +24 -0
  29. data/app/lib/actions/katello/alternate_content_source/destroy.rb +27 -0
  30. data/app/lib/actions/katello/alternate_content_source/refresh.rb +27 -0
  31. data/app/lib/actions/katello/alternate_content_source/update.rb +41 -0
  32. data/app/lib/actions/katello/cdn_configuration/update.rb +3 -3
  33. data/app/lib/actions/katello/content_view/destroy.rb +2 -1
  34. data/app/lib/actions/katello/content_view/incremental_updates.rb +7 -3
  35. data/app/lib/actions/katello/content_view/publish.rb +8 -10
  36. data/app/lib/actions/katello/content_view_version/auto_create_products.rb +4 -4
  37. data/app/lib/actions/katello/content_view_version/auto_create_redhat_repositories.rb +6 -4
  38. data/app/lib/actions/katello/content_view_version/auto_create_repositories.rb +6 -4
  39. data/app/lib/actions/katello/content_view_version/import.rb +25 -22
  40. data/app/lib/actions/katello/content_view_version/import_library.rb +0 -1
  41. data/app/lib/actions/katello/content_view_version/import_repository.rb +21 -0
  42. data/app/lib/actions/katello/content_view_version/incremental_update.rb +85 -93
  43. data/app/lib/actions/katello/content_view_version/reset_content_view_repositories_from_metadata.rb +2 -2
  44. data/app/lib/actions/katello/organization/manifest_refresh.rb +1 -1
  45. data/app/lib/actions/katello/product/content_create.rb +10 -8
  46. data/app/lib/actions/katello/repository/destroy.rb +36 -12
  47. data/app/lib/actions/katello/repository_set/disable_repository.rb +8 -3
  48. data/app/lib/actions/pulp3/alternate_content_source/create.rb +20 -0
  49. data/app/lib/actions/pulp3/alternate_content_source/create_remote.rb +20 -0
  50. data/app/lib/actions/pulp3/alternate_content_source/delete.rb +16 -0
  51. data/app/lib/actions/pulp3/alternate_content_source/delete_remote.rb +16 -0
  52. data/app/lib/actions/pulp3/alternate_content_source/refresh.rb +23 -0
  53. data/app/lib/actions/pulp3/alternate_content_source/update.rb +16 -0
  54. data/app/lib/actions/pulp3/alternate_content_source/update_remote.rb +17 -0
  55. data/app/lib/actions/pulp3/content_view_version/{import.rb → create_import.rb} +5 -5
  56. data/app/lib/actions/pulp3/content_view_version/create_importer.rb +4 -3
  57. data/app/lib/actions/pulp3/content_view_version/destroy_importer.rb +12 -1
  58. data/app/lib/actions/pulp3/orchestration/alternate_content_source/create.rb +16 -0
  59. data/app/lib/actions/pulp3/orchestration/alternate_content_source/delete.rb +23 -0
  60. data/app/lib/actions/pulp3/orchestration/alternate_content_source/refresh.rb +15 -0
  61. data/app/lib/actions/pulp3/orchestration/alternate_content_source/update.rb +16 -0
  62. data/app/lib/actions/pulp3/orchestration/content_view_version/copy_version_units_to_library.rb +1 -1
  63. data/app/lib/actions/pulp3/orchestration/content_view_version/export_repository.rb +51 -0
  64. data/app/lib/actions/pulp3/orchestration/content_view_version/import.rb +5 -2
  65. data/app/lib/actions/pulp3/repository/refresh_distribution.rb +1 -4
  66. data/app/lib/actions/pulp3/repository/save_artifact.rb +1 -1
  67. data/app/lib/actions/pulp3/repository/save_distribution_references.rb +0 -2
  68. data/app/lib/katello/api/v2/error_handling.rb +1 -0
  69. data/app/lib/katello/resources/cdn/katello_cdn.rb +3 -1
  70. data/app/lib/katello/util/errata.rb +2 -3
  71. data/app/lib/katello/validators/alternate_content_source_path_validator.rb +29 -0
  72. data/app/lib/katello/validators/content_default_http_proxy_setting_validator.rb +12 -0
  73. data/app/lib/katello/validators/content_view_environment_validator.rb +10 -5
  74. data/app/models/katello/alternate_content_source.rb +71 -0
  75. data/app/models/katello/authorization/alternate_content_source.rb +33 -0
  76. data/app/models/katello/authorization/repository.rb +3 -3
  77. data/app/models/katello/candlepin/repository_mapper.rb +13 -6
  78. data/app/models/katello/cdn_configuration.rb +15 -15
  79. data/app/models/katello/concerns/content_facet_host_extensions.rb +25 -0
  80. data/app/models/katello/concerns/host_managed_extensions.rb +7 -5
  81. data/app/models/katello/concerns/http_proxy_extensions.rb +14 -0
  82. data/app/models/katello/concerns/organization_extensions.rb +4 -2
  83. data/app/models/katello/concerns/setting_extensions.rb +14 -0
  84. data/app/models/katello/concerns/smart_proxy_extensions.rb +2 -1
  85. data/app/models/katello/content.rb +1 -0
  86. data/app/models/katello/content_credential.rb +6 -0
  87. data/app/models/katello/content_override.rb +7 -3
  88. data/app/models/katello/content_view.rb +33 -2
  89. data/app/models/katello/content_view_erratum_filter.rb +26 -12
  90. data/app/models/katello/content_view_filter.rb +4 -0
  91. data/app/models/katello/content_view_version.rb +12 -0
  92. data/app/models/katello/content_view_version_export_history.rb +3 -1
  93. data/app/models/katello/erratum.rb +9 -5
  94. data/app/models/katello/events/delete_latest_content_view_version.rb +40 -0
  95. data/app/models/katello/host/content_facet.rb +14 -0
  96. data/app/models/katello/host_available_module_stream.rb +12 -0
  97. data/app/models/katello/product_content.rb +1 -0
  98. data/app/models/katello/purpose_sla_status.rb +1 -1
  99. data/app/models/katello/purpose_status.rb +2 -2
  100. data/app/models/katello/repository.rb +7 -4
  101. data/app/models/katello/root_repository.rb +1 -1
  102. data/app/models/katello/smart_proxy_alternate_content_source.rb +8 -0
  103. data/app/models/katello/sync_plan.rb +1 -1
  104. data/app/presenters/katello/product_content_presenter.rb +15 -0
  105. data/app/services/katello/applicable_host_queue.rb +1 -1
  106. data/app/services/katello/product_content_finder.rb +12 -2
  107. data/app/services/katello/pulp3/alternate_content_source.rb +123 -0
  108. data/app/services/katello/pulp3/api/file.rb +8 -0
  109. data/app/services/katello/pulp3/api/yum.rb +8 -0
  110. data/app/services/katello/pulp3/content_view_version/export.rb +27 -5
  111. data/app/services/katello/pulp3/content_view_version/import.rb +97 -71
  112. data/app/services/katello/pulp3/content_view_version/import_export_common.rb +4 -4
  113. data/app/services/katello/pulp3/content_view_version/import_gpg_keys.rb +13 -11
  114. data/app/services/katello/pulp3/content_view_version/import_validator.rb +67 -72
  115. data/app/services/katello/pulp3/content_view_version/importable_products.rb +40 -24
  116. data/app/services/katello/pulp3/content_view_version/importable_repositories.rb +88 -39
  117. data/app/services/katello/pulp3/content_view_version/metadata_generator.rb +2 -2
  118. data/app/services/katello/pulp3/content_view_version/metadata_map.rb +117 -0
  119. data/app/services/katello/pulp3/erratum.rb +1 -1
  120. data/app/services/katello/pulp3/pulp_content_unit.rb +6 -1
  121. data/app/services/katello/pulp3/repository/yum.rb +70 -12
  122. data/app/services/katello/pulp3/repository.rb +35 -63
  123. data/app/services/katello/pulp3/service_common.rb +66 -0
  124. data/app/services/katello/pulp3/smart_proxy_mirror_repository.rb +4 -1
  125. data/app/services/katello/ui_notifications/content_view/delete_latest_version_failure.rb +22 -0
  126. data/app/views/foreman/job_templates/change_content_source.erb +1 -1
  127. data/app/views/foreman/job_templates/install_errata.erb +5 -5
  128. data/app/views/foreman/job_templates/install_errata_by_search_query.erb +7 -6
  129. data/app/views/foreman/job_templates/install_group.erb +4 -4
  130. data/app/views/foreman/job_templates/install_package.erb +4 -4
  131. data/app/views/foreman/job_templates/install_packages_by_search_query.erb +3 -3
  132. data/app/views/foreman/job_templates/remove_group.erb +4 -4
  133. data/app/views/foreman/job_templates/remove_package.erb +4 -4
  134. data/app/views/foreman/job_templates/remove_packages_by_search_query.erb +3 -3
  135. data/app/views/foreman/job_templates/resolve_traces.erb +2 -2
  136. data/app/views/foreman/job_templates/restart_services.erb +3 -3
  137. data/app/views/foreman/job_templates/update_group.erb +4 -4
  138. data/app/views/foreman/job_templates/update_package.erb +4 -4
  139. data/app/views/foreman/job_templates/update_packages_by_search_query.erb +3 -3
  140. data/app/views/foreman/smart_proxies/show.html.erb +2 -0
  141. data/app/views/katello/api/v2/alternate_content_sources/base.json.rabl +24 -0
  142. data/app/views/katello/api/v2/alternate_content_sources/index.json.rabl +7 -0
  143. data/app/views/katello/api/v2/alternate_content_sources/show.json.rabl +3 -0
  144. data/app/views/katello/api/v2/capsule_content/sync_status.json.rabl +1 -1
  145. data/app/views/katello/api/v2/content_facet/show.json.rabl +12 -0
  146. data/app/views/katello/api/v2/content_view_version_export_histories/show.json.rabl +2 -3
  147. data/app/views/katello/api/v2/content_view_versions/base.json.rabl +1 -1
  148. data/app/views/katello/api/v2/content_views/base.json.rabl +1 -0
  149. data/app/views/katello/api/v2/environments/show.json.rabl +2 -0
  150. data/app/views/katello/api/v2/errata/_counts.json.rabl +2 -2
  151. data/app/views/katello/api/v2/host_module_streams/base.json.rabl +2 -2
  152. data/app/views/katello/api/v2/hosts/host_collections.json.rabl +1 -1
  153. data/app/views/katello/api/v2/module_streams/show.json.rabl +0 -7
  154. data/app/views/katello/api/v2/organizations/show.json.rabl +7 -1
  155. data/app/views/katello/api/v2/repositories/show.json.rabl +2 -1
  156. data/app/views/katello/api/v2/repository_sets/show.json.rabl +4 -0
  157. data/app/views/katello/sync_management/_repo.html.erb +8 -29
  158. data/config/routes/api/v2.rb +19 -0
  159. data/db/migrate/20150930183738_migrate_content_hosts.rb +0 -399
  160. data/db/migrate/20171025163149_remove_use_pulp_oauth_setting.rb +1 -1
  161. data/db/migrate/20171114150937_cleanup_installed_packages.rb +1 -1
  162. data/db/migrate/20180402160223_clean_up_force_post_sync_action_setting.rb +1 -1
  163. data/db/migrate/20211129200124_remove_dependency_solving_algorithm_setting.rb +1 -1
  164. data/db/migrate/20211220185935_clean_duplicate_content_units.rb +1 -1
  165. data/db/migrate/20220110223754_update_disconnected_settings.rb +5 -5
  166. data/db/migrate/20220117151612_add_alternate_content_sources.rb +48 -0
  167. data/db/migrate/20220124191056_add_type_to_cdn_configuration.rb +9 -4
  168. data/db/migrate/20220209203251_add_generated_for_to_content_views.rb +13 -0
  169. data/db/migrate/20220209205137_expand_sync_timeout_settings.rb +7 -7
  170. data/db/migrate/20220228173251_remove_drpm_from_ignorable_content.rb +12 -0
  171. data/db/migrate/20220303160220_remove_duplicate_errata.rb +37 -2
  172. data/db/migrate/20220404190836_delete_old_setting_data.rb +9 -0
  173. data/db/migrate/20220405220616_update_cdn_configuration_type.rb +11 -0
  174. data/db/migrate/20220419193414_content_settings_to_dsl_category.rb +5 -0
  175. data/db/migrate/20220428203334_add_last_refreshed_to_katello_alternate_content_sources.rb +5 -0
  176. data/db/seeds.d/110-content-view-autopublish.rb +13 -0
  177. data/db/seeds.d/150-module_job_templates.rb +1 -1
  178. data/engines/bastion/README.md +1 -0
  179. data/engines/bastion/app/assets/javascripts/bastion/components/bst-modal.directive.js +1 -0
  180. data/engines/bastion/app/views/bastion/layouts/assets.html.erb +1 -0
  181. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/activation-keys/details/activation-key-details.controller.js +4 -2
  182. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/capsule-content/capsule-content.controller.js +11 -6
  183. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/content-hosts/content/content-host-module-streams.controller.js +1 -0
  184. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/content-hosts/content/content-host-packages-installed.controller.js +1 -0
  185. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/content-hosts/content/content-host-traces.controller.js +1 -0
  186. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/content-hosts/content/views/content-host-packages-actions.html +1 -1
  187. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/content-hosts/content/views/content-host-packages-applicable.html +1 -1
  188. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/content-hosts/content-hosts.controller.js +8 -0
  189. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/content-hosts/details/content-host-details.controller.js +4 -2
  190. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/content-hosts/views/content-hosts.html +2 -2
  191. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/environments/content.service.js +10 -0
  192. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/environments/details/views/environment-deb-repositories.html +26 -0
  193. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/environments/details/views/environment-debs.html +27 -0
  194. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/environments/environments.controller.js +1 -0
  195. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/environments/environments.routes.js +22 -0
  196. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/environments/views/environments.html +13 -7
  197. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/i18n/bastion_katello.pot +63 -17
  198. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/products/details/repositories/details/repository-details-info.controller.js +7 -8
  199. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/products/details/repositories/details/repository-details.controller.js +10 -1
  200. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/products/details/repositories/details/views/repository-details.html +21 -3
  201. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/products/details/repositories/details/views/repository-info.html +8 -9
  202. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/products/details/repositories/mirroring-policy.service.js +1 -1
  203. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/products/details/repositories/new/new-repository.controller.js +7 -5
  204. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/products/details/repositories/new/views/new-repository.html +2 -1
  205. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/products/discovery/discovery-create.controller.js +1 -1
  206. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/products/discovery/views/discovery-create.html +1 -1
  207. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/products/products.routes.js +1 -0
  208. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/subscriptions/views/content-access-mode-banner.html +6 -1
  209. data/lib/katello/engine.rb +1 -5
  210. data/lib/katello/permission_creator.rb +34 -4
  211. data/lib/katello/plugin.rb +377 -3
  212. data/lib/katello/tasks/refresh_alternate_content_sources.rake +10 -0
  213. data/lib/katello/tasks/reset.rake.bak +67 -0
  214. data/lib/katello/tasks/update_content_default_http_proxy.rake +2 -3
  215. data/lib/katello/version.rb +1 -1
  216. data/locale/action_names.rb +47 -41
  217. data/locale/bn/LC_MESSAGES/katello.mo +0 -0
  218. data/locale/bn/katello.po +820 -106
  219. data/locale/bn/katello.po.time_stamp +0 -0
  220. data/locale/cs/LC_MESSAGES/katello.mo +0 -0
  221. data/locale/cs/katello.po +818 -104
  222. data/locale/cs/katello.po.time_stamp +0 -0
  223. data/locale/de/LC_MESSAGES/katello.mo +0 -0
  224. data/locale/de/katello.po +893 -179
  225. data/locale/de/katello.po.time_stamp +0 -0
  226. data/locale/en/LC_MESSAGES/katello.mo +0 -0
  227. data/locale/en/katello.po +817 -103
  228. data/locale/en/katello.po.time_stamp +0 -0
  229. data/locale/es/LC_MESSAGES/katello.mo +0 -0
  230. data/locale/es/katello.po +882 -168
  231. data/locale/es/katello.po.time_stamp +0 -0
  232. data/locale/fr/LC_MESSAGES/katello.mo +0 -0
  233. data/locale/fr/katello.po +1219 -505
  234. data/locale/fr/katello.po.time_stamp +0 -0
  235. data/locale/gu/LC_MESSAGES/katello.mo +0 -0
  236. data/locale/gu/katello.po +826 -112
  237. data/locale/gu/katello.po.time_stamp +0 -0
  238. data/locale/hi/LC_MESSAGES/katello.mo +0 -0
  239. data/locale/hi/katello.po +826 -112
  240. data/locale/hi/katello.po.time_stamp +0 -0
  241. data/locale/it/LC_MESSAGES/katello.mo +0 -0
  242. data/locale/it/katello.po +863 -148
  243. data/locale/it/katello.po.time_stamp +0 -0
  244. data/locale/ja/LC_MESSAGES/katello.mo +0 -0
  245. data/locale/ja/katello.po +1216 -499
  246. data/locale/ja/katello.po.time_stamp +0 -0
  247. data/locale/katello.pot +3847 -2507
  248. data/locale/kn/LC_MESSAGES/katello.mo +0 -0
  249. data/locale/kn/katello.po +826 -112
  250. data/locale/kn/katello.po.time_stamp +0 -0
  251. data/locale/ko/LC_MESSAGES/katello.mo +0 -0
  252. data/locale/ko/katello.po +912 -198
  253. data/locale/ko/katello.po.time_stamp +0 -0
  254. data/locale/mr/LC_MESSAGES/katello.mo +0 -0
  255. data/locale/mr/katello.po +826 -112
  256. data/locale/mr/katello.po.time_stamp +0 -0
  257. data/locale/or/LC_MESSAGES/katello.mo +0 -0
  258. data/locale/or/katello.po +826 -112
  259. data/locale/or/katello.po.time_stamp +0 -0
  260. data/locale/pa/LC_MESSAGES/katello.mo +0 -0
  261. data/locale/pa/katello.po +826 -112
  262. data/locale/pa/katello.po.time_stamp +0 -0
  263. data/locale/pt/LC_MESSAGES/katello.mo +0 -0
  264. data/locale/pt/katello.po +817 -103
  265. data/locale/pt/katello.po.time_stamp +0 -0
  266. data/locale/pt_BR/LC_MESSAGES/katello.mo +0 -0
  267. data/locale/pt_BR/katello.po +879 -165
  268. data/locale/pt_BR/katello.po.time_stamp +0 -0
  269. data/locale/ru/LC_MESSAGES/katello.mo +0 -0
  270. data/locale/ru/katello.po +927 -213
  271. data/locale/ru/katello.po.time_stamp +0 -0
  272. data/locale/ta/LC_MESSAGES/katello.mo +0 -0
  273. data/locale/ta/katello.po +820 -106
  274. data/locale/ta/katello.po.time_stamp +0 -0
  275. data/locale/te/LC_MESSAGES/katello.mo +0 -0
  276. data/locale/te/katello.po +826 -112
  277. data/locale/te/katello.po.time_stamp +0 -0
  278. data/locale/zh_CN/LC_MESSAGES/katello.mo +0 -0
  279. data/locale/zh_CN/katello.po +1202 -486
  280. data/locale/zh_CN/katello.po.time_stamp +0 -0
  281. data/locale/zh_TW/LC_MESSAGES/katello.mo +0 -0
  282. data/locale/zh_TW/katello.po +856 -142
  283. data/locale/zh_TW/katello.po.time_stamp +0 -0
  284. data/webpack/components/Bookmark/index.js +22 -14
  285. data/webpack/components/EditableTextInput/EditableTextInput.js +20 -5
  286. data/webpack/components/Errata/index.js +38 -8
  287. data/webpack/components/Packages/index.js +1 -4
  288. data/webpack/components/Search/Search.js +22 -3
  289. data/webpack/components/SelectAllCheckbox/index.js +1 -0
  290. data/webpack/components/SelectableDropdown/SelectableDropdown.js +4 -2
  291. data/webpack/components/Table/EmptyStateMessage.js +21 -7
  292. data/webpack/components/Table/MainTable.js +29 -4
  293. data/webpack/components/Table/MainTable.scss +5 -1
  294. data/webpack/components/Table/TableHooks.js +65 -20
  295. data/webpack/components/Table/TableWrapper.js +9 -3
  296. data/webpack/components/Table/components/SortableColumnHeaders.js +19 -0
  297. data/webpack/components/Table/components/TranslatedPlural.js +57 -0
  298. data/webpack/components/TypeAhead/TypeAhead.js +12 -0
  299. data/webpack/components/TypeAhead/pf4Search/TypeAheadInput.js +13 -11
  300. data/webpack/components/TypeAhead/pf4Search/TypeAheadSearch.js +7 -2
  301. data/webpack/components/extensions/HostDetails/ActionsBar/index.js +27 -0
  302. data/webpack/components/extensions/HostDetails/Cards/ContentViewDetailsCard/ChangeHostCVModal.js +250 -0
  303. data/webpack/components/extensions/HostDetails/Cards/ContentViewDetailsCard/ContentViewDetailsCard.js +232 -0
  304. data/webpack/components/extensions/HostDetails/Cards/ContentViewDetailsCard/HostContentViewActions.js +19 -0
  305. data/webpack/components/extensions/HostDetails/Cards/ContentViewDetailsCard/HostContentViewConstants.js +2 -0
  306. data/webpack/components/extensions/HostDetails/Cards/ContentViewDetailsCard/__tests__/changeHostCVModal.test.js +131 -0
  307. data/webpack/components/extensions/HostDetails/Cards/{__tests__ → ContentViewDetailsCard/__tests__}/contentViewDetailsCard.test.js +22 -0
  308. data/webpack/components/extensions/HostDetails/Cards/ContentViewDetailsCard/__tests__/contentViews.fixtures.json +443 -0
  309. data/webpack/components/extensions/HostDetails/Cards/ContentViewDetailsCard/__tests__/envPaths.fixtures.json +320 -0
  310. data/webpack/components/extensions/HostDetails/Cards/ErrataOverviewCard.js +57 -33
  311. data/webpack/components/extensions/HostDetails/Cards/ErrataOverviewCard.scss +3 -0
  312. data/webpack/components/extensions/HostDetails/Cards/HostCollectionsCard/HostCollectionsActions.js +30 -0
  313. data/webpack/components/extensions/HostDetails/Cards/HostCollectionsCard/HostCollectionsCard.js +206 -0
  314. data/webpack/components/extensions/HostDetails/Cards/HostCollectionsCard/HostCollectionsConstants.js +7 -0
  315. data/webpack/components/extensions/HostDetails/Cards/HostCollectionsCard/HostCollectionsModal.js +227 -0
  316. data/webpack/components/extensions/HostDetails/Cards/HostCollectionsCard/HostCollectionsSelectors.js +18 -0
  317. data/webpack/components/extensions/HostDetails/Cards/HostCollectionsCard/__tests__/availableHostCollections.fixtures.json +106 -0
  318. data/webpack/components/extensions/HostDetails/Cards/HostCollectionsCard/__tests__/hostCollectionsCard.test.js +118 -0
  319. data/webpack/components/extensions/HostDetails/Cards/HostCollectionsCard/__tests__/hostCollectionsModal.test.js +235 -0
  320. data/webpack/components/extensions/HostDetails/Cards/HostCollectionsCard/__tests__/removableHostCollections.fixtures.json +45 -0
  321. data/webpack/components/extensions/HostDetails/Cards/__tests__/errataOverviewCard.test.js +33 -8
  322. data/webpack/components/extensions/HostDetails/DetailsTabCards/InstalledProductsCard.js +44 -0
  323. data/webpack/components/extensions/HostDetails/DetailsTabCards/RecentCommunicationCardExtensions.js +37 -0
  324. data/webpack/components/extensions/HostDetails/DetailsTabCards/RegistrationCard.js +107 -0
  325. data/webpack/components/extensions/HostDetails/DetailsTabCards/SystemPropertiesCardExtensions.js +38 -0
  326. data/webpack/components/extensions/HostDetails/HostDetailsActions.js +11 -0
  327. data/webpack/components/extensions/HostDetails/Tabs/ContentTab/SecondaryTabsRoutes.js +4 -0
  328. data/webpack/components/extensions/HostDetails/Tabs/ContentTab/constants.js +2 -0
  329. data/webpack/components/extensions/HostDetails/Tabs/ContentTab/index.js +6 -1
  330. data/webpack/components/extensions/HostDetails/Tabs/ErrataTab/ErrataTab.js +176 -72
  331. data/webpack/components/extensions/HostDetails/Tabs/ErrataTab/HostErrataActions.js +1 -7
  332. data/webpack/components/extensions/HostDetails/Tabs/ModuleStreamsTab/ModuleStreamsActions.js +1 -3
  333. data/webpack/components/extensions/HostDetails/Tabs/ModuleStreamsTab/ModuleStreamsConstants.js +28 -0
  334. data/webpack/components/extensions/HostDetails/Tabs/ModuleStreamsTab/ModuleStreamsTab.js +522 -118
  335. data/webpack/components/extensions/HostDetails/Tabs/PackagesTab/HostPackagesActions.js +1 -7
  336. data/webpack/components/extensions/HostDetails/Tabs/PackagesTab/PackageInstallModal.js +6 -4
  337. data/webpack/components/extensions/HostDetails/Tabs/PackagesTab/PackagesTab.js +164 -58
  338. data/webpack/components/extensions/HostDetails/Tabs/RemoteExecutionActions.js +59 -49
  339. data/webpack/components/extensions/HostDetails/Tabs/RemoteExecutionConstants.js +1 -0
  340. data/webpack/components/extensions/HostDetails/Tabs/RemoteExecutionHooks.js +85 -0
  341. data/webpack/components/extensions/HostDetails/Tabs/RepositorySetsTab/RepositorySetsActions.js +33 -54
  342. data/webpack/components/extensions/HostDetails/Tabs/RepositorySetsTab/RepositorySetsConstants.js +20 -0
  343. data/webpack/components/extensions/HostDetails/Tabs/RepositorySetsTab/RepositorySetsTab.js +298 -107
  344. data/webpack/components/extensions/HostDetails/Tabs/TracesTab/EnableTracerModal.js +14 -7
  345. data/webpack/components/extensions/HostDetails/Tabs/TracesTab/HostTracesActions.js +2 -1
  346. data/webpack/components/extensions/HostDetails/Tabs/TracesTab/TracesEnabler.js +104 -0
  347. data/webpack/components/extensions/HostDetails/Tabs/TracesTab/TracesTab.js +134 -57
  348. data/webpack/components/extensions/HostDetails/Tabs/__tests__/errataTab.test.js +37 -32
  349. data/webpack/components/extensions/HostDetails/Tabs/{ModuleStreamsTab/__tests__/modules.fixtures.json → __tests__/moduleStreams.fixtures.json} +6 -3
  350. data/webpack/components/extensions/HostDetails/Tabs/__tests__/moduleStreamsTab.test.js +261 -0
  351. data/webpack/components/extensions/HostDetails/Tabs/__tests__/packageInstallModal.test.js +21 -15
  352. data/webpack/components/extensions/HostDetails/Tabs/__tests__/packagesTab.test.js +44 -1
  353. data/webpack/components/extensions/HostDetails/Tabs/__tests__/repositorySets.fixtures.json +4 -1
  354. data/webpack/components/extensions/HostDetails/Tabs/__tests__/repositorySetsTab.test.js +105 -6
  355. data/webpack/components/extensions/HostDetails/Tabs/__tests__/tracesTab.test.js +25 -6
  356. data/webpack/components/extensions/HostDetails/Tabs/customizedRexUrlHelpers.js +6 -0
  357. data/webpack/components/extensions/HostDetails/hostDetailsHelpers.js +18 -0
  358. data/webpack/containers/Application/config.js +5 -0
  359. data/webpack/global_index.js +32 -9
  360. data/webpack/global_test_setup.js +13 -0
  361. data/webpack/redux/actions/RedHatRepositories/enabled.js +2 -1
  362. data/webpack/redux/actions/RedHatRepositories/helpers.js +13 -8
  363. data/webpack/scenes/AlternateContentSources/ACSActions.js +65 -0
  364. data/webpack/scenes/AlternateContentSources/ACSConstants.js +18 -0
  365. data/webpack/scenes/AlternateContentSources/ACSIndexPage.js +23 -0
  366. data/webpack/scenes/AlternateContentSources/ACSSelectors.js +24 -0
  367. data/webpack/scenes/AlternateContentSources/Create/ACSCreateContext.js +4 -0
  368. data/webpack/scenes/AlternateContentSources/Create/ACSCreateWizard.js +160 -0
  369. data/webpack/scenes/AlternateContentSources/Create/Steps/ACSCreateFinish.js +79 -0
  370. data/webpack/scenes/AlternateContentSources/Create/Steps/ACSCredentials.js +199 -0
  371. data/webpack/scenes/AlternateContentSources/Create/Steps/ACSReview.js +104 -0
  372. data/webpack/scenes/AlternateContentSources/Create/Steps/ACSSmartProxies.js +41 -0
  373. data/webpack/scenes/AlternateContentSources/Create/Steps/AcsUrlPaths.js +71 -0
  374. data/webpack/scenes/AlternateContentSources/Create/Steps/NameACS.js +57 -0
  375. data/webpack/scenes/AlternateContentSources/Create/Steps/SelectSource.js +77 -0
  376. data/webpack/scenes/AlternateContentSources/Create/__tests__/acsCreate.test.js +149 -0
  377. data/webpack/scenes/AlternateContentSources/Create/__tests__/acsCreateData.fixtures.json +3 -0
  378. data/webpack/scenes/AlternateContentSources/Create/__tests__/contentCredentials.fixtures.json +69 -0
  379. data/webpack/scenes/AlternateContentSources/Create/__tests__/smartProxy.fixtures.json +65 -0
  380. data/webpack/scenes/AlternateContentSources/MainTable/ACSTable.js +162 -0
  381. data/webpack/scenes/AlternateContentSources/MainTable/__tests__/acsIndex.fixtures.json +91 -0
  382. data/webpack/scenes/AlternateContentSources/MainTable/__tests__/acsTable.test.js +67 -0
  383. data/webpack/scenes/AlternateContentSources/index.js +4 -0
  384. data/webpack/scenes/Content/Details/ContentRepositories.js +1 -0
  385. data/webpack/scenes/Content/Table/ContentTable.js +1 -0
  386. data/webpack/scenes/ContentCredentials/ContentCredentialSelectors.js +4 -1
  387. data/webpack/scenes/ContentViews/ContentViewsActions.js +6 -2
  388. data/webpack/scenes/ContentViews/ContentViewsConstants.js +11 -3
  389. data/webpack/scenes/ContentViews/Copy/CopyContentViewForm.js +2 -1
  390. data/webpack/scenes/ContentViews/Create/ContentViewFormComponents.js +10 -1
  391. data/webpack/scenes/ContentViews/Create/CreateContentViewForm.js +4 -3
  392. data/webpack/scenes/ContentViews/Create/__tests__/createContentView.test.js +1 -1
  393. data/webpack/scenes/ContentViews/Delete/ContentViewDeleteWizard.js +7 -5
  394. data/webpack/scenes/ContentViews/Delete/Steps/CVDeletionFinish.js +29 -21
  395. data/webpack/scenes/ContentViews/Delete/__tests__/contentViewDelete.test.js +15 -8
  396. data/webpack/scenes/ContentViews/Details/ComponentContentViews/ComponentContentViewAddModal.js +3 -3
  397. data/webpack/scenes/ContentViews/Details/ComponentContentViews/ComponentContentViewBulkAddModal.js +4 -4
  398. data/webpack/scenes/ContentViews/Details/ComponentContentViews/ContentViewComponents.js +3 -1
  399. data/webpack/scenes/ContentViews/Details/ComponentContentViews/__tests__/contentViewComponents.test.js +4 -4
  400. data/webpack/scenes/ContentViews/Details/ContentViewDetailActions.js +34 -8
  401. data/webpack/scenes/ContentViews/Details/ContentViewDetailSelectors.js +33 -29
  402. data/webpack/scenes/ContentViews/Details/ContentViewDetails.js +130 -79
  403. data/webpack/scenes/ContentViews/Details/ContentViewInfo.js +17 -3
  404. data/webpack/scenes/ContentViews/Details/Filters/Add/CVFilterAddModal.js +2 -1
  405. data/webpack/scenes/ContentViews/Details/Filters/AffectedRepositories/AffectedRepositoryTable.js +2 -1
  406. data/webpack/scenes/ContentViews/Details/Filters/CVContainerImageFilterContent.js +6 -1
  407. data/webpack/scenes/ContentViews/Details/Filters/CVErrataDateFilterContent.js +41 -21
  408. data/webpack/scenes/ContentViews/Details/Filters/CVErrataIDFilterContent.js +38 -20
  409. data/webpack/scenes/ContentViews/Details/Filters/CVModuleStreamFilterContent.js +2 -0
  410. data/webpack/scenes/ContentViews/Details/Filters/CVPackageGroupFilterContent.js +8 -1
  411. data/webpack/scenes/ContentViews/Details/Filters/CVRpmFilterContent.js +9 -1
  412. data/webpack/scenes/ContentViews/Details/Filters/ContentViewFilters.js +2 -1
  413. data/webpack/scenes/ContentViews/Details/Filters/MatchContentModal/CVRpmMatchContentModal.js +1 -0
  414. data/webpack/scenes/ContentViews/Details/Filters/Rules/ContainerTag/AddEditContainerTagRuleModal.js +27 -12
  415. data/webpack/scenes/ContentViews/Details/Filters/Rules/Package/AddEditPackageRuleModal.js +39 -17
  416. data/webpack/scenes/ContentViews/Details/Filters/__tests__/CVContainerImageFilterContent.test.js +27 -10
  417. data/webpack/scenes/ContentViews/Details/Filters/__tests__/CVRpmFilterContent.test.js +46 -23
  418. data/webpack/scenes/ContentViews/Details/Histories/ContentViewHistories.js +3 -2
  419. data/webpack/scenes/ContentViews/Details/Promote/ContentViewVersionPromote.js +5 -2
  420. data/webpack/scenes/ContentViews/Details/Repositories/ContentViewRepositories.js +161 -108
  421. data/webpack/scenes/ContentViews/Details/Repositories/__tests__/contentViewAddRemove.test.js +7 -7
  422. data/webpack/scenes/ContentViews/Details/Repositories/__tests__/contentViewRepoAdd.fixture.json +1 -0
  423. data/webpack/scenes/ContentViews/Details/Versions/BulkDelete/ActionSummary.js +58 -0
  424. data/webpack/scenes/ContentViews/Details/Versions/BulkDelete/BulkDeleteContextWrapper.js +45 -0
  425. data/webpack/scenes/ContentViews/Details/Versions/BulkDelete/BulkDeleteHelpers.js +30 -0
  426. data/webpack/scenes/ContentViews/Details/Versions/BulkDelete/BulkDeleteModal.js +56 -0
  427. data/webpack/scenes/ContentViews/Details/Versions/BulkDelete/Steps/ConfirmBulkDelete.js +126 -0
  428. data/webpack/scenes/ContentViews/Details/Versions/BulkDelete/Steps/FinishBulkDelete.js +61 -0
  429. data/webpack/scenes/ContentViews/Details/Versions/BulkDelete/Steps/ReassignActivationKeys.js +196 -0
  430. data/webpack/scenes/ContentViews/Details/Versions/BulkDelete/Steps/ReassignHosts.js +220 -0
  431. data/webpack/scenes/ContentViews/Details/Versions/BulkDelete/Steps/ReviewEnvironments.js +104 -0
  432. data/webpack/scenes/ContentViews/Details/Versions/BulkDelete/__tests__/BulkDeleteModal.test.js +122 -0
  433. data/webpack/scenes/ContentViews/Details/Versions/BulkDelete/__tests__/BulkDeleteVersions.fixtures.json +600 -0
  434. data/webpack/scenes/ContentViews/Details/Versions/BulkDelete/__tests__/contentView.fixtures.json +1504 -0
  435. data/webpack/scenes/ContentViews/Details/Versions/BulkDelete/__tests__/contentViewVersion.fixtures.json +936 -0
  436. data/webpack/scenes/ContentViews/Details/Versions/BulkDelete/__tests__/environmentPaths.fixtures.json +261 -0
  437. data/webpack/scenes/ContentViews/Details/Versions/BulkDelete/__tests__/hosts.fixtures.json +163 -0
  438. data/webpack/scenes/ContentViews/Details/Versions/BulkDelete/bulkDeleteSteps.js +79 -0
  439. data/webpack/scenes/ContentViews/Details/Versions/ContentViewVersions.js +192 -167
  440. data/webpack/scenes/ContentViews/Details/Versions/Delete/RemoveCVVersionWizard.js +2 -5
  441. data/webpack/scenes/ContentViews/Details/Versions/Delete/RemoveSteps/CVVersionDeleteFinish.js +38 -53
  442. data/webpack/scenes/ContentViews/Details/Versions/Delete/RemoveSteps/CVVersionRemoveReview.js +1 -1
  443. data/webpack/scenes/ContentViews/Details/Versions/Delete/__tests__/cvVersionRemove.test.js +6 -12
  444. data/webpack/scenes/ContentViews/Details/Versions/Delete/affectedActivationKeys.js +1 -0
  445. data/webpack/scenes/ContentViews/Details/Versions/Delete/affectedHosts.js +1 -0
  446. data/webpack/scenes/ContentViews/Details/Versions/VersionDetails/ContentViewVersionDetailConfig.js +1 -0
  447. data/webpack/scenes/ContentViews/Details/Versions/VersionDetails/ContentViewVersionDetails.js +8 -20
  448. data/webpack/scenes/ContentViews/Details/Versions/VersionDetails/ContentViewVersionDetailsHeader.js +23 -13
  449. data/webpack/scenes/ContentViews/Details/Versions/VersionDetails/ContentViewVersionDetailsTable.js +3 -0
  450. data/webpack/scenes/ContentViews/Details/Versions/VersionDetails/__tests__/ContentViewVersionDetails.fixtures.json +4 -4
  451. data/webpack/scenes/ContentViews/Details/Versions/VersionDetails/__tests__/ContentViewVersionDetails.test.js +0 -3
  452. data/webpack/scenes/ContentViews/Details/Versions/VersionDetails/__tests__/ContentViewVersionDetailsEmpty.test.js +4 -4
  453. data/webpack/scenes/ContentViews/Details/Versions/__tests__/contentViewVersions.test.js +12 -14
  454. data/webpack/scenes/ContentViews/Details/__tests__/contentViewDetails.fixtures.json +1 -0
  455. data/webpack/scenes/ContentViews/Publish/CVPublishFinish.js +96 -117
  456. data/webpack/scenes/ContentViews/Publish/PublishContentViewWizard.js +13 -19
  457. data/webpack/scenes/ContentViews/Publish/__tests__/publishContentView.test.js +9 -20
  458. data/webpack/scenes/ContentViews/Table/ContentViewsTable.js +165 -148
  459. data/webpack/scenes/ContentViews/Table/tableDataGenerator.js +2 -0
  460. data/webpack/scenes/ContentViews/__tests__/contentViewPage.test.js +4 -4
  461. data/webpack/scenes/ContentViews/components/ContentViewIcon.js +14 -3
  462. data/webpack/scenes/ContentViews/components/ContentViewsCounter.js +1 -1
  463. data/webpack/scenes/ContentViews/components/EnvironmentLabels.js +4 -3
  464. data/webpack/scenes/ContentViews/components/EnvironmentPaths/EnvironmentPaths.js +10 -6
  465. data/webpack/scenes/ContentViews/components/EnvironmentPaths/EnvironmentPaths.scss +6 -1
  466. data/webpack/scenes/ContentViews/components/TaskPresenter/TaskPresenter.js +40 -35
  467. data/webpack/scenes/ContentViews/expansions/DetailsExpansion.js +2 -2
  468. data/webpack/scenes/ContentViews/expansions/RelatedCompositeContentViewsModal.js +1 -1
  469. data/webpack/scenes/ContentViews/expansions/RelatedContentViewComponentsModal.js +4 -4
  470. data/webpack/scenes/ContentViews/expansions/__tests__/contentViewComponentsModal.test.js +1 -1
  471. data/webpack/scenes/ContentViews/helpers.js +3 -0
  472. data/webpack/scenes/Hosts/ChangeContentSource/helpers.js +5 -0
  473. data/webpack/scenes/ModuleStreams/Details/ModuleDetailsSchema.js +1 -10
  474. data/webpack/scenes/ModuleStreams/Details/ModuleStreamDetails.js +13 -14
  475. data/webpack/scenes/ModuleStreams/Details/__tests__/__snapshots__/ModuleStreamDetails.test.js.snap +17 -100
  476. data/webpack/scenes/RedHatRepositories/RedHatRepositoriesPage.js +3 -3
  477. data/webpack/scenes/RedHatRepositories/components/EnabledRepository/EnabledRepository.js +2 -1
  478. data/webpack/scenes/RedHatRepositories/components/EnabledRepository/__tests__/EnabledRepository.test.js +2 -0
  479. data/webpack/scenes/RedHatRepositories/components/Search.js +4 -4
  480. data/webpack/scenes/SmartProxy/SmartProxyContentActions.js +9 -2
  481. data/webpack/scenes/SmartProxy/SmartProxyContentConstants.js +1 -1
  482. data/webpack/scenes/SmartProxy/SmartProxyContentSelectors.js +10 -1
  483. data/webpack/scenes/Subscriptions/Manifest/CdnConfigurationTab/CdnConfigurationConstants.js +3 -3
  484. data/webpack/scenes/Subscriptions/Manifest/CdnConfigurationTab/CdnTypeForm.js +2 -0
  485. data/webpack/scenes/Subscriptions/Manifest/CdnConfigurationTab/{AirGappedTypeForm.js → ExportSyncForm.js} +7 -6
  486. data/webpack/scenes/Subscriptions/Manifest/CdnConfigurationTab/{UpstreamServerTypeForm.js → NetworkSyncForm.js} +15 -7
  487. data/webpack/scenes/Subscriptions/Manifest/CdnConfigurationTab/__tests__/{AirGappedTypeForm.test.js → ExportSyncForm.test.js} +4 -4
  488. data/webpack/scenes/Subscriptions/Manifest/CdnConfigurationTab/__tests__/{UpstreamServerTypeForm.test.js → NetworkSyncForm.test.js} +8 -8
  489. data/webpack/scenes/Subscriptions/Manifest/CdnConfigurationTab/index.js +11 -11
  490. data/webpack/scenes/Subscriptions/SubscriptionConstants.js +1 -0
  491. data/webpack/scenes/Subscriptions/SubscriptionsPage.js +8 -7
  492. data/webpack/scenes/Tasks/TaskActions.js +6 -0
  493. data/webpack/scenes/Tasks/TaskSelectors.js +11 -0
  494. data/webpack/scenes/Tasks/helpers.js +60 -5
  495. data/webpack/utils/helpers.js +2 -0
  496. metadata +186 -41
  497. data/app/models/setting/content.rb +0 -201
  498. data/db/seeds.d/107-enable_dynflow.rb +0 -8
  499. data/webpack/components/extensions/HostDetails/Cards/ContentViewDetailsCard.js +0 -96
  500. data/webpack/components/extensions/HostDetails/Tabs/ModuleStreamsTab/__tests__/moduleStreamsTab.test.js +0 -108
  501. data/webpack/components/extensions/HostDetails/Tabs/TracesTab/EnableTracerEmptyState.js +0 -42
  502. data/webpack/scenes/ContentViews/Details/DetailsContainer.js +0 -36
@@ -0,0 +1,261 @@
1
+ import React from 'react';
2
+ import { act } from 'react-test-renderer';
3
+ import { renderWithRedux, patientlyWaitFor, within, fireEvent } from 'react-testing-lib-wrapper';
4
+ import { nockInstance, assertNockRequest, mockForemanAutocomplete, mockSetting } from '../../../../../test-utils/nockWrapper';
5
+ import { ModuleStreamsTab } from '../ModuleStreamsTab/ModuleStreamsTab.js';
6
+ import mockModuleStreams from './moduleStreams.fixtures.json';
7
+ import mockBookmarkData from './bookmarks.fixtures.json';
8
+ import { MODULE_STREAMS_KEY } from '../../../../../scenes/ModuleStreams/ModuleStreamsConstants';
9
+ import { foremanApi } from '../../../../../services/api';
10
+
11
+ jest.mock('../../hostDetailsHelpers', () => ({
12
+ ...jest.requireActual('../../hostDetailsHelpers'),
13
+ userPermissionsFromHostDetails: () => ({
14
+ create_job_invocations: true,
15
+ }),
16
+ }));
17
+
18
+ const moduleBookmarks = foremanApi.getApiUrl('/bookmarks?search=controller%3Dkatello_host_available_module_streams');
19
+
20
+ const contentFacetAttributes = {
21
+ id: 11,
22
+ uuid: 'e5761ea3-4117-4ecf-83d0-b694f99b389e',
23
+ content_view_default: false,
24
+ lifecycle_environment_library: false,
25
+ };
26
+
27
+ const renderOptions = (facetAttributes = contentFacetAttributes) => ({
28
+ apiNamespace: MODULE_STREAMS_KEY,
29
+ initialState: {
30
+ API: {
31
+ HOST_DETAILS: {
32
+ response: {
33
+ id: 1,
34
+ name: 'test-host',
35
+ content_facet_attributes: { ...facetAttributes },
36
+ },
37
+ status: 'RESOLVED',
38
+ },
39
+ },
40
+ },
41
+ });
42
+
43
+ const hostModuleStreams = foremanApi.getApiUrl('/hosts/1/module_streams');
44
+ const autocompleteUrl = '/hosts/1/module_streams/auto_complete_search';
45
+
46
+ let firstModuleStreams;
47
+ let searchDelayScope;
48
+ let autoSearchScope;
49
+ let bookmarkScope;
50
+
51
+ beforeEach(() => {
52
+ const { results } = mockModuleStreams;
53
+ [firstModuleStreams] = results;
54
+ bookmarkScope = nockInstance.get(moduleBookmarks).reply(200, mockBookmarkData);
55
+ searchDelayScope = mockSetting(nockInstance, 'autosearch_delay', 0);
56
+ autoSearchScope = mockSetting(nockInstance, 'autosearch_while_typing');
57
+ });
58
+
59
+ afterEach(() => {
60
+ assertNockRequest(searchDelayScope);
61
+ assertNockRequest(autoSearchScope);
62
+ assertNockRequest(bookmarkScope);
63
+ });
64
+
65
+ beforeEach(() => {
66
+ const { results } = mockModuleStreams;
67
+ [firstModuleStreams] = results;
68
+ searchDelayScope = mockSetting(nockInstance, 'autosearch_delay', 0);
69
+ autoSearchScope = mockSetting(nockInstance, 'autosearch_while_typing');
70
+ });
71
+
72
+ afterEach(() => {
73
+ assertNockRequest(searchDelayScope);
74
+ assertNockRequest(autoSearchScope);
75
+ });
76
+
77
+ test('Can call API for Module streams and show on screen on page load', async (done) => {
78
+ // Setup autocomplete with mockForemanAutoComplete since we aren't adding /katello
79
+ const autocompleteScope = mockForemanAutocomplete(nockInstance, autocompleteUrl);
80
+ const scope = nockInstance
81
+ .get(hostModuleStreams)
82
+ .query(true)
83
+ .reply(200, mockModuleStreams);
84
+
85
+ const { getAllByText } = renderWithRedux(<ModuleStreamsTab />, renderOptions());
86
+
87
+ // Assert that the Module streams are now showing on the screen, but wait for them to appear.
88
+ await patientlyWaitFor(() =>
89
+ expect(getAllByText(firstModuleStreams.name)[0]).toBeInTheDocument());
90
+ // Assert request was made and completed, see helper function
91
+ assertNockRequest(autocompleteScope);
92
+ assertNockRequest(scope, done); // Pass jest callback to confirm test is done
93
+ act(done);
94
+ });
95
+
96
+ test('Can handle no Module streams being present', async (done) => {
97
+ // Setup autocomplete with mockForemanAutoComplete since we aren't adding /katello
98
+ const autocompleteScope = mockForemanAutocomplete(nockInstance, autocompleteUrl);
99
+
100
+ const noResults = {
101
+ total: 0,
102
+ subtotal: 0,
103
+ page: 1,
104
+ per_page: 20,
105
+ results: [],
106
+ };
107
+
108
+ const scope = nockInstance
109
+ .get(hostModuleStreams)
110
+ .query(true)
111
+ .reply(200, noResults);
112
+
113
+ const { queryByText } = renderWithRedux(<ModuleStreamsTab />, renderOptions());
114
+
115
+ // Assert that there are not any Module streams showing on the screen.
116
+ await patientlyWaitFor(() => expect(queryByText('This host does not have any Module streams.')).toBeInTheDocument());
117
+ // Assert request was made and completed, see helper function
118
+ assertNockRequest(autocompleteScope);
119
+ assertNockRequest(scope, done); // Pass jest callback to confirm test is done
120
+ act(done);
121
+ });
122
+
123
+ test('Can filter results based on status', async (done) => {
124
+ const autocompleteScope = mockForemanAutocomplete(nockInstance, autocompleteUrl);
125
+ const scope = nockInstance
126
+ .get(hostModuleStreams)
127
+ .query(true)
128
+ .reply(200, mockModuleStreams);
129
+
130
+ const scope2 = nockInstance
131
+ .get(hostModuleStreams)
132
+ .query(true)
133
+ .reply(200, mockModuleStreams);
134
+
135
+ const {
136
+ queryByLabelText,
137
+ getByRole,
138
+ getAllByText,
139
+ } = renderWithRedux(<ModuleStreamsTab />, renderOptions());
140
+
141
+ // Assert that the Module streams are now showing on the screen, but wait for them to appear.
142
+ await patientlyWaitFor(() =>
143
+ expect(getAllByText(firstModuleStreams.name)[0]).toBeInTheDocument());
144
+ const typeContainer = queryByLabelText('select Status container', { ignore: 'th' });
145
+ const typeDropdown = within(typeContainer).queryByText('Status');
146
+ expect(typeDropdown).toBeInTheDocument();
147
+ fireEvent.click(typeDropdown);
148
+ const installed = getByRole('option', { name: 'select Installed' });
149
+ fireEvent.click(installed);
150
+ assertNockRequest(autocompleteScope);
151
+ assertNockRequest(scope);
152
+ assertNockRequest(scope2, done);
153
+ act(done);
154
+ });
155
+
156
+ test('Can filter results based on Installation status', async (done) => {
157
+ const autocompleteScope = mockForemanAutocomplete(nockInstance, autocompleteUrl);
158
+ const scope = nockInstance
159
+ .get(hostModuleStreams)
160
+ .query(true)
161
+ .reply(200, mockModuleStreams);
162
+
163
+ const scope2 = nockInstance
164
+ .get(hostModuleStreams)
165
+ .query(true)
166
+ .reply(200, mockModuleStreams);
167
+
168
+ const {
169
+ queryByLabelText,
170
+ getByRole,
171
+ getAllByText,
172
+ } = renderWithRedux(<ModuleStreamsTab />, renderOptions());
173
+
174
+ // Assert that the Module streams are now showing on the screen, but wait for them to appear.
175
+ await patientlyWaitFor(() =>
176
+ expect(getAllByText(firstModuleStreams.name)[0]).toBeInTheDocument());
177
+ const typeContainer = queryByLabelText('select Installation status container', { ignore: 'th' });
178
+ const typeDropdown = within(typeContainer).queryByText('Installation status');
179
+ expect(typeDropdown).toBeInTheDocument();
180
+ fireEvent.click(typeDropdown);
181
+ const installed = getByRole('option', { name: 'select Upgradable' });
182
+ fireEvent.click(installed);
183
+ assertNockRequest(autocompleteScope);
184
+ assertNockRequest(scope);
185
+ assertNockRequest(scope2, done);
186
+ act(done);
187
+ });
188
+
189
+ test('Can provide dropdown actions with redirects on Module Streams with customized Rex', async (done) => {
190
+ const autocompleteScope = mockForemanAutocomplete(nockInstance, autocompleteUrl);
191
+ const scope = nockInstance
192
+ .get(hostModuleStreams)
193
+ .query(true)
194
+ .reply(200, mockModuleStreams);
195
+
196
+ const {
197
+ queryByLabelText,
198
+ getByText,
199
+ getAllByText,
200
+ getByLabelText,
201
+ } = renderWithRedux(<ModuleStreamsTab />, renderOptions());
202
+
203
+ // Assert that the Module streams are now showing on the screen, but wait for them to appear.
204
+ await patientlyWaitFor(() =>
205
+ expect(getAllByText(firstModuleStreams.name)[0]).toBeInTheDocument());
206
+ expect(queryByLabelText('kebab-dropdown-3')).toBeInTheDocument();
207
+ fireEvent.click(queryByLabelText('kebab-dropdown-3'));
208
+ await patientlyWaitFor(() => expect(getByLabelText('customize-checkbox-3')).toBeInTheDocument());
209
+ fireEvent.click(getByLabelText('customize-checkbox-3'));
210
+ await patientlyWaitFor(() => expect(getByText('Enable')).toBeInTheDocument());
211
+ expect(getByText('Enable')).toHaveAttribute('href', '/job_invocations/new?feature=katello_module_stream_action&host_ids=name%20%5E%20(test-host)&inputs%5Baction%5D=enable&inputs%5Bmodule_spec%5D=walrus:2.4');
212
+ expect(getByText('Install')).toHaveAttribute('href', '/job_invocations/new?feature=katello_module_stream_action&host_ids=name%20%5E%20(test-host)&inputs%5Baction%5D=install&inputs%5Bmodule_spec%5D=walrus:2.4');
213
+ assertNockRequest(autocompleteScope);
214
+ assertNockRequest(scope, done);
215
+ act(done);
216
+ });
217
+
218
+ test('Can perform actions on Module Streams', async (done) => {
219
+ const jobInvocationURL = foremanApi.getApiUrl('/job_invocations');
220
+ const exampleRemoveAction = {
221
+ job_invocation:
222
+ {
223
+ feature: 'katello_module_stream_action',
224
+ inputs: {
225
+ action: 'remove',
226
+ module_spec: 'walrus:2.4',
227
+ },
228
+ search_query: 'name ^ (test-host)',
229
+ },
230
+ };
231
+ const autocompleteScope = mockForemanAutocomplete(nockInstance, autocompleteUrl);
232
+ const scope = nockInstance
233
+ .get(hostModuleStreams)
234
+ .query(true)
235
+ .reply(200, mockModuleStreams);
236
+
237
+ const jobScope = nockInstance
238
+ .post(jobInvocationURL, exampleRemoveAction)
239
+ .reply(200, { id: 'dummy_id', description: 'Remove action dummy response' });
240
+
241
+ const {
242
+ queryByLabelText,
243
+ getByText,
244
+ getAllByText,
245
+ getByLabelText,
246
+ } = renderWithRedux(<ModuleStreamsTab />, renderOptions());
247
+
248
+ // Assert that the Module streams are now showing on the screen, but wait for them to appear.
249
+ await patientlyWaitFor(() =>
250
+ expect(getAllByText(firstModuleStreams.name)[0]).toBeInTheDocument());
251
+ expect(queryByLabelText('kebab-dropdown-3')).toBeInTheDocument();
252
+ fireEvent.click(queryByLabelText('kebab-dropdown-3'));
253
+ await patientlyWaitFor(() => expect(getByText('Enable')).toBeInTheDocument());
254
+ fireEvent.click(getByText('Remove'));
255
+ expect(getByLabelText('confirm-module-action')).toBeInTheDocument();
256
+ fireEvent.click(getByLabelText('confirm-module-action'));
257
+ assertNockRequest(autocompleteScope);
258
+ assertNockRequest(scope);
259
+ assertNockRequest(jobScope, done);
260
+ act(done);
261
+ });
@@ -4,9 +4,17 @@ import { nockInstance, assertNockRequest, mockForemanAutocomplete, mockSetting }
4
4
  import katelloApi, { foremanApi } from '../../../../../services/api';
5
5
  import mockPackagesData from './yumInstallablePackages.fixtures.json';
6
6
  import PackageInstallModal from '../PackagesTab/PackageInstallModal';
7
- import { HOST_YUM_INSTALLABLE_PACKAGES_KEY, PACKAGE_SEARCH_QUERY } from '../PackagesTab/YumInstallablePackagesConstants';
7
+ import { HOST_YUM_INSTALLABLE_PACKAGES_KEY } from '../PackagesTab/YumInstallablePackagesConstants';
8
8
  import { REX_FEATURES } from '../RemoteExecutionConstants';
9
9
 
10
+ jest.mock('../../hostDetailsHelpers', () => ({
11
+ ...jest.requireActual('../../hostDetailsHelpers'),
12
+ userPermissionsFromHostDetails: () => ({
13
+ create_job_invocations: true,
14
+ edit_hosts: true,
15
+ }),
16
+ }));
17
+
10
18
  const contentFacetAttributes = {
11
19
  id: 11,
12
20
  uuid: 'e5761ea3-4117-4ecf-83d0-b694f99b389e',
@@ -32,7 +40,6 @@ const renderOptions = (facetAttributes = contentFacetAttributes) => ({
32
40
 
33
41
  const hostYumInstallablePackages = katelloApi.getApiUrl('/packages');
34
42
  const hostPackages = foremanApi.getApiUrl('/hosts/1/packages/install');
35
- const jobInvocations = foremanApi.getApiUrl('/job_invocations');
36
43
  const autocompleteUrl = '/hosts/1/packages/auto_complete_search';
37
44
  const fakeTask = { id: '21c0f9e4-b27b-49aa-8774-6be66126043b' };
38
45
 
@@ -77,6 +84,7 @@ test('Can call API for installable packages and show on screen on page load', as
77
84
  hostId={1}
78
85
  hostName="test-host"
79
86
  showKatelloAgent={false}
87
+ triggerPackageInstall={jest.fn()}
80
88
  />, renderOptions());
81
89
 
82
90
  // Assert that the packages are now showing on the screen, but wait for them to appear.
@@ -109,6 +117,7 @@ test('Can handle no installable packages being present', async (done) => {
109
117
  hostId={1}
110
118
  hostName="test-host"
111
119
  showKatelloAgent={false}
120
+ triggerPackageInstall={jest.fn()}
112
121
  />, renderOptions());
113
122
 
114
123
  // Assert that there are not any packages showing on the screen.
@@ -134,6 +143,7 @@ test('Does not show katello-agent option when disabled', async (done) => {
134
143
  hostId={1}
135
144
  hostName="test-host"
136
145
  showKatelloAgent={false}
146
+ triggerPackageInstall={jest.fn()}
137
147
  />, renderOptions());
138
148
 
139
149
  // Assert that the packages are now showing on the screen, but wait for them to appear.
@@ -172,6 +182,7 @@ test('Shows the katello-agent option when enabled', async (done) => {
172
182
  hostId={1}
173
183
  hostName="test-host"
174
184
  showKatelloAgent
185
+ triggerPackageInstall={jest.fn()}
175
186
  />, renderOptions());
176
187
 
177
188
  // Assert that the packages are now showing on the screen, but wait for them to appear.
@@ -209,6 +220,7 @@ test('Can install packages via katello-agent', async (done) => {
209
220
  hostId={1}
210
221
  hostName="test-host"
211
222
  showKatelloAgent
223
+ triggerPackageInstall={jest.fn()}
212
224
  />, renderOptions());
213
225
 
214
226
  await patientlyWaitFor(() => expect(getAllByText(firstPackages.name)[0]).toBeInTheDocument());
@@ -236,17 +248,7 @@ test('Can install a package via remote execution', async (done) => {
236
248
  .get(hostYumInstallablePackages)
237
249
  .query(defaultQuery)
238
250
  .reply(200, mockPackagesData);
239
- const installScope = nockInstance
240
- .post(jobInvocations, {
241
- job_invocation: {
242
- inputs: {
243
- [PACKAGE_SEARCH_QUERY]: `id ^ (${firstPackages.id},${secondPackages.id})`,
244
- },
245
- search_query: 'name ^ (test-host)',
246
- feature: REX_FEATURES.KATELLO_PACKAGE_INSTALL_BY_SEARCH,
247
- },
248
- })
249
- .reply(201);
251
+ const triggerPackageInstall = jest.fn();
250
252
 
251
253
  const {
252
254
  getAllByText, getByText, getByRole,
@@ -256,6 +258,7 @@ test('Can install a package via remote execution', async (done) => {
256
258
  hostId={1}
257
259
  hostName="test-host"
258
260
  showKatelloAgent
261
+ triggerPackageInstall={triggerPackageInstall}
259
262
  />, renderOptions());
260
263
 
261
264
  await patientlyWaitFor(() => expect(getAllByText(firstPackages.name)[0]).toBeInTheDocument());
@@ -271,9 +274,9 @@ test('Can install a package via remote execution', async (done) => {
271
274
  const rexOption = getByText('Install via remote execution');
272
275
  fireEvent.click(rexOption);
273
276
 
277
+ expect(triggerPackageInstall).toHaveBeenCalled();
274
278
  assertNockRequest(autocompleteScope);
275
- assertNockRequest(scope);
276
- assertNockRequest(installScope, done);
279
+ assertNockRequest(scope, done);
277
280
  });
278
281
 
279
282
  test('Can install a package via customized remote execution', async (done) => {
@@ -290,6 +293,7 @@ test('Can install a package via customized remote execution', async (done) => {
290
293
  closeModal={jest.fn()}
291
294
  hostId={1}
292
295
  hostName="test-host"
296
+ triggerPackageInstall={jest.fn()}
293
297
  />, renderOptions());
294
298
 
295
299
  await patientlyWaitFor(() => expect(getAllByText(firstPackages.name)[0]).toBeInTheDocument());
@@ -326,6 +330,7 @@ test('Uses package_install_by_search_query template when in select all mode', as
326
330
  closeModal={jest.fn()}
327
331
  hostId={1}
328
332
  hostName="test-host"
333
+ triggerPackageInstall={jest.fn()}
329
334
  />, renderOptions());
330
335
 
331
336
  await patientlyWaitFor(() => expect(getAllByText(firstPackages.name)[0]).toBeInTheDocument());
@@ -364,6 +369,7 @@ test('Disables the katello-agent option when in select all mode', async (done) =
364
369
  hostId={1}
365
370
  hostName="test-host"
366
371
  showKatelloAgent
372
+ triggerPackageInstall={jest.fn()}
367
373
  />, renderOptions());
368
374
 
369
375
  await patientlyWaitFor(() => expect(getAllByText(firstPackages.name)[0]).toBeInTheDocument());
@@ -6,6 +6,16 @@ import { HOST_PACKAGES_KEY, PACKAGES_SEARCH_QUERY } from '../PackagesTab/HostPac
6
6
  import { PackagesTab } from '../PackagesTab/PackagesTab.js';
7
7
  import mockPackagesData from './packages.fixtures.json';
8
8
  import { REX_FEATURES } from '../RemoteExecutionConstants';
9
+ import * as hooks from '../../../../Table/TableHooks';
10
+ import mockBookmarkData from './bookmarks.fixtures.json';
11
+
12
+ jest.mock('../../hostDetailsHelpers', () => ({
13
+ ...jest.requireActual('../../hostDetailsHelpers'),
14
+ userPermissionsFromHostDetails: () => ({
15
+ create_job_invocations: true,
16
+ edit_hosts: true,
17
+ }),
18
+ }));
9
19
 
10
20
  const contentFacetAttributes = {
11
21
  id: 11,
@@ -15,6 +25,8 @@ const contentFacetAttributes = {
15
25
  };
16
26
 
17
27
  const hostname = 'test-host.example.com';
28
+ const packageBookmarks = foremanApi.getApiUrl('/bookmarks?search=controller%3Dkatello_host_installed_packages');
29
+
18
30
  const renderOptions = (facetAttributes = contentFacetAttributes) => ({
19
31
  apiNamespace: HOST_PACKAGES_KEY,
20
32
  initialState: {
@@ -34,21 +46,29 @@ const renderOptions = (facetAttributes = contentFacetAttributes) => ({
34
46
  const hostPackages = foremanApi.getApiUrl('/hosts/1/packages');
35
47
  const jobInvocations = foremanApi.getApiUrl('/job_invocations');
36
48
  const autocompleteUrl = '/hosts/1/packages/auto_complete_search';
37
- const defaultQueryWithoutSearch = {
49
+ const baseQuery = {
38
50
  include_latest_upgradable: true,
39
51
  per_page: 20,
40
52
  page: 1,
41
53
  };
54
+
55
+ const defaultQueryWithoutSearch = {
56
+ ...baseQuery,
57
+ sort_by: 'nvra',
58
+ sort_order: 'asc',
59
+ };
42
60
  const defaultQuery = { ...defaultQueryWithoutSearch, search: '' };
43
61
 
44
62
  let firstPackage;
45
63
  let secondPackage;
46
64
  let searchDelayScope;
47
65
  let autoSearchScope;
66
+ let bookmarkScope;
48
67
 
49
68
  beforeEach(() => {
50
69
  const { results } = mockPackagesData;
51
70
  [firstPackage, secondPackage] = results;
71
+ bookmarkScope = nockInstance.get(packageBookmarks).reply(200, mockBookmarkData);
52
72
  searchDelayScope = mockSetting(nockInstance, 'autosearch_delay', 0);
53
73
  autoSearchScope = mockSetting(nockInstance, 'autosearch_while_typing');
54
74
  });
@@ -56,6 +76,7 @@ beforeEach(() => {
56
76
  afterEach(() => {
57
77
  assertNockRequest(searchDelayScope);
58
78
  assertNockRequest(autoSearchScope);
79
+ assertNockRequest(bookmarkScope);
59
80
  });
60
81
 
61
82
  test('Can call API for packages and show on screen on page load', async (done) => {
@@ -390,3 +411,25 @@ test('Remove is disabled when in select all mode', async (done) => {
390
411
  assertNockRequest(autocompleteScope);
391
412
  assertNockRequest(scope, done);
392
413
  });
414
+
415
+ test('Sets initial search query from url params', async (done) => {
416
+ // Setup autocomplete with mockForemanAutoComplete since we aren't adding /katello
417
+ const autocompleteScope = mockForemanAutocomplete(nockInstance, autocompleteUrl);
418
+ const scope = nockInstance
419
+ .get(hostPackages)
420
+ .query({ ...defaultQuery, search: `name=${firstPackage.name}` })
421
+ .reply(200, { ...mockPackagesData, results: [firstPackage] });
422
+
423
+ jest.spyOn(hooks, 'useUrlParams').mockImplementation(() => ({
424
+ searchParam: `name=${firstPackage.name}`,
425
+ }));
426
+
427
+ const { getAllByText, queryByText } = renderWithRedux(<PackagesTab />, renderOptions());
428
+
429
+ await patientlyWaitFor(() => expect(getAllByText(firstPackage.name)[0]).toBeInTheDocument());
430
+ expect(queryByText(secondPackage.name)).not.toBeInTheDocument();
431
+
432
+ assertNockRequest(autocompleteScope);
433
+ assertNockRequest(scope, done); // Pass jest callback to confirm test is done
434
+ });
435
+
@@ -41,6 +41,7 @@
41
41
  "type": "yum",
42
42
  "gpgUrl": null,
43
43
  "contentUrl": "/custom/ParthaProduct/empty_repo",
44
+ "osRestricted": null,
44
45
  "override": "default",
45
46
  "overrides": [],
46
47
  "enabled_content_override": null
@@ -75,6 +76,7 @@
75
76
  "type": "yum",
76
77
  "gpgUrl": null,
77
78
  "contentUrl": "/custom/ParthaProduct/partha_multi-errata",
79
+ "osRestricted": "rhel-7",
78
80
  "override": "0",
79
81
  "overrides": [
80
82
  {
@@ -107,6 +109,7 @@
107
109
  "type": "yum",
108
110
  "gpgUrl": null,
109
111
  "contentUrl": "/custom/Pull_Provider/yggdrasil",
112
+ "osRestricted": null,
110
113
  "override": "1",
111
114
  "overrides": [
112
115
  {
@@ -117,4 +120,4 @@
117
120
  "enabled_content_override": true
118
121
  }
119
122
  ]
120
- }
123
+ }
@@ -1,5 +1,5 @@
1
1
  import React from 'react';
2
- import { renderWithRedux, patientlyWaitFor, fireEvent } from 'react-testing-lib-wrapper';
2
+ import { renderWithRedux, patientlyWaitFor, within, fireEvent } from 'react-testing-lib-wrapper';
3
3
  import { nockInstance, assertNockRequest, mockAutocomplete, mockSetting } from '../../../../../test-utils/nockWrapper';
4
4
  import katelloApi, { foremanApi } from '../../../../../services/api';
5
5
  import { REPOSITORY_SETS_KEY } from '../RepositorySetsTab/RepositorySetsConstants';
@@ -8,6 +8,16 @@ import mockRepoSetData from './repositorySets.fixtures.json';
8
8
  import mockBookmarkData from './bookmarks.fixtures.json';
9
9
  import mockContentOverride from './contentOverrides.fixtures.json';
10
10
 
11
+ jest.mock('../../hostDetailsHelpers', () => ({
12
+ ...jest.requireActual('../../hostDetailsHelpers'),
13
+ userPermissionsFromHostDetails: () => ({
14
+ view_hosts: true,
15
+ view_activation_keys: true,
16
+ view_products: true,
17
+ edit_hosts: true,
18
+ }),
19
+ }));
20
+
11
21
  const contentFacetAttributes = {
12
22
  id: 11,
13
23
  uuid: 'e5761ea3-4117-4ecf-83d0-b694f99b389e',
@@ -43,6 +53,8 @@ const defaultQuery = {
43
53
  per_page: 20,
44
54
  page: 1,
45
55
  search: '',
56
+ sort_by: 'name',
57
+ sort_order: 'asc',
46
58
  };
47
59
  const libraryQuery = {
48
60
  ...defaultQuery,
@@ -50,6 +62,7 @@ const libraryQuery = {
50
62
  };
51
63
 
52
64
  let firstRepoSet;
65
+ let secondRepoSet;
53
66
  let searchDelayScope;
54
67
  let autoSearchScope;
55
68
  let bookmarkScope;
@@ -57,7 +70,7 @@ let bookmarkScope;
57
70
  beforeEach(() => {
58
71
  // jest.resetModules();
59
72
  const { results } = mockRepoSetData;
60
- [firstRepoSet] = results;
73
+ [firstRepoSet, secondRepoSet] = results;
61
74
  bookmarkScope = nockInstance.get(repositorySetBookmarks).reply(200, mockBookmarkData);
62
75
  searchDelayScope = mockSetting(nockInstance, 'autosearch_delay', 0);
63
76
  autoSearchScope = mockSetting(nockInstance, 'autosearch_while_typing');
@@ -204,9 +217,11 @@ test('Can override to disabled', async (done) => {
204
217
  .get(hostRepositorySets)
205
218
  .query(defaultQuery)
206
219
  .reply(200, mockRepoSetData);
220
+ const overrides = JSON.parse(JSON.stringify(mockContentOverride));
221
+ overrides.results[0].enabled_content_override = false;
207
222
  const contentOverrideScope = nockInstance
208
223
  .put(contentOverride)
209
- .reply(200, mockContentOverride);
224
+ .reply(200, overrides);
210
225
 
211
226
  const { getByText, getAllByText, getAllByLabelText } =
212
227
  renderWithRedux(<RepositorySetsTab />, renderOptions());
@@ -240,9 +255,12 @@ test('Can override to enabled', async (done) => {
240
255
  .get(hostRepositorySets)
241
256
  .query(defaultQuery)
242
257
  .reply(200, mockRepoSetData);
258
+ const overrides = JSON.parse(JSON.stringify(mockContentOverride));
259
+ overrides.results[1].enabled_content_override = true;
260
+
243
261
  const contentOverrideScope = nockInstance
244
262
  .put(contentOverride)
245
- .reply(200, mockContentOverride);
263
+ .reply(200, overrides);
246
264
 
247
265
  const {
248
266
  getByText, queryByText, getAllByText, getAllByLabelText,
@@ -276,10 +294,12 @@ test('Can reset to default', async (done) => {
276
294
  .get(hostRepositorySets)
277
295
  .query(defaultQuery)
278
296
  .reply(200, mockRepoSetData);
297
+ const overrides = JSON.parse(JSON.stringify(mockContentOverride));
298
+ overrides.results[1].enabled_content_override = null;
299
+
279
300
  const contentOverrideScope = nockInstance
280
301
  .put(contentOverride)
281
- .reply(200, mockContentOverride);
282
-
302
+ .reply(200, overrides);
283
303
  const {
284
304
  getByText, queryByText, getAllByText, getAllByLabelText,
285
305
  } = renderWithRedux(<RepositorySetsTab />, renderOptions());
@@ -288,6 +308,7 @@ test('Can reset to default', async (done) => {
288
308
  await patientlyWaitFor(() => expect(getByText(firstRepoSet.contentUrl)).toBeInTheDocument());
289
309
  expect(getAllByText('Enabled')).toHaveLength(2);
290
310
  expect(getAllByText('Disabled')).toHaveLength(1);
311
+
291
312
  // The second item is overridden to disabled but would normally be enabled; we're going to reset
292
313
  const actionMenu = getAllByLabelText('Actions')[1].closest('button');
293
314
  fireEvent.click(actionMenu);
@@ -305,3 +326,81 @@ test('Can reset to default', async (done) => {
305
326
  assertNockRequest(scope);
306
327
  assertNockRequest(contentOverrideScope, done); // Pass jest callback to confirm test is done
307
328
  });
329
+
330
+ test('Can override in bulk', async (done) => {
331
+ const autocompleteScope = mockAutocomplete(nockInstance, autocompleteUrl);
332
+ const scope = nockInstance
333
+ .get(hostRepositorySets)
334
+ .query(defaultQuery)
335
+ .reply(200, mockRepoSetData);
336
+ const contentOverrideScope = nockInstance
337
+ .put(contentOverride)
338
+ .reply(200, mockContentOverride);
339
+
340
+ const {
341
+ getByText, getByLabelText, queryByText,
342
+ } = renderWithRedux(<RepositorySetsTab />, renderOptions());
343
+
344
+ await patientlyWaitFor(() => expect(getByText(firstRepoSet.contentUrl)).toBeInTheDocument());
345
+ getByLabelText('Select row 0').click();
346
+ getByLabelText('Select row 1').click();
347
+ const actionMenu = getByLabelText('bulk_actions');
348
+ actionMenu.click();
349
+ const resetToDefault = queryByText('Reset to default');
350
+ expect(resetToDefault).toBeInTheDocument();
351
+ resetToDefault.click();
352
+
353
+ assertNockRequest(autocompleteScope);
354
+ assertNockRequest(scope);
355
+ assertNockRequest(contentOverrideScope, done); // Pass jest callback to confirm test is done});
356
+ });
357
+
358
+ test('Can filter by status', async (done) => {
359
+ const autocompleteScope = mockAutocomplete(nockInstance, autocompleteUrl);
360
+ const scope = nockInstance
361
+ .get(hostRepositorySets)
362
+ .query(defaultQuery)
363
+ .reply(200, mockRepoSetData);
364
+
365
+ const scope2 = nockInstance
366
+ .get(hostRepositorySets)
367
+ .query({ ...defaultQuery, status: 'overridden' })
368
+ .reply(200, { ...mockRepoSetData, results: [secondRepoSet] });
369
+
370
+ const {
371
+ getByText, queryByLabelText, getByRole,
372
+ } = renderWithRedux(<RepositorySetsTab />, renderOptions());
373
+
374
+ await patientlyWaitFor(() => expect(getByText(firstRepoSet.contentUrl)).toBeInTheDocument());
375
+
376
+ const statusContainer = queryByLabelText('select Status container', { ignore: 'th' });
377
+ const statusDropdown = within(statusContainer).queryByText('Status');
378
+ expect(statusDropdown).toBeInTheDocument();
379
+ fireEvent.click(statusDropdown);
380
+ const overridden = getByRole('option', { name: 'select Overridden' });
381
+ fireEvent.click(overridden);
382
+ await patientlyWaitFor(() => {
383
+ expect(getByText('Overridden')).toBeInTheDocument();
384
+ });
385
+ assertNockRequest(autocompleteScope);
386
+ assertNockRequest(scope);
387
+ assertNockRequest(searchDelayScope);
388
+ assertNockRequest(autoSearchScope);
389
+ assertNockRequest(scope2, done); // Pass jest callback to confirm test is done
390
+ });
391
+
392
+ test('Can display osRestricted as a label', async (done) => {
393
+ const autocompleteScope = mockAutocomplete(nockInstance, autocompleteUrl);
394
+ const scope = nockInstance
395
+ .get(hostRepositorySets)
396
+ .query(defaultQuery)
397
+ .reply(200, mockRepoSetData);
398
+
399
+ const { getByText } = renderWithRedux(<RepositorySetsTab />, renderOptions());
400
+
401
+ await patientlyWaitFor(() => expect(getByText(secondRepoSet.contentUrl)).toBeInTheDocument());
402
+ expect(secondRepoSet.osRestricted).not.toBeNull();
403
+ expect(getByText(secondRepoSet.osRestricted)).toBeInTheDocument();
404
+ assertNockRequest(autocompleteScope);
405
+ assertNockRequest(scope, done); // Pass jest callback to confirm test is done
406
+ });