katello 4.4.1 → 4.5.0

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


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

Files changed (488) 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/host_module_streams_controller.rb +8 -2
  16. data/app/controllers/katello/api/v2/host_subscriptions_controller.rb +25 -3
  17. data/app/controllers/katello/api/v2/organizations_controller.rb +4 -2
  18. data/app/controllers/katello/api/v2/repositories_bulk_actions_controller.rb +1 -1
  19. data/app/controllers/katello/api/v2/repositories_controller.rb +1 -1
  20. data/app/controllers/katello/api/v2/repository_sets_controller.rb +40 -7
  21. data/app/controllers/katello/api/v2/subscriptions_controller.rb +2 -2
  22. data/app/controllers/katello/concerns/api/v2/hosts_controller_extensions.rb +1 -1
  23. data/app/helpers/katello/concerns/smart_proxy_helper_extensions.rb +4 -0
  24. data/app/helpers/katello/hosts_and_hostgroups_helper.rb +21 -3
  25. data/app/lib/actions/katello/alternate_content_source/create.rb +24 -0
  26. data/app/lib/actions/katello/alternate_content_source/destroy.rb +27 -0
  27. data/app/lib/actions/katello/alternate_content_source/refresh.rb +27 -0
  28. data/app/lib/actions/katello/alternate_content_source/update.rb +41 -0
  29. data/app/lib/actions/katello/cdn_configuration/update.rb +3 -3
  30. data/app/lib/actions/katello/content_view/destroy.rb +2 -1
  31. data/app/lib/actions/katello/content_view/incremental_updates.rb +7 -3
  32. data/app/lib/actions/katello/content_view/publish.rb +8 -10
  33. data/app/lib/actions/katello/content_view_version/auto_create_products.rb +4 -4
  34. data/app/lib/actions/katello/content_view_version/auto_create_redhat_repositories.rb +6 -4
  35. data/app/lib/actions/katello/content_view_version/auto_create_repositories.rb +6 -4
  36. data/app/lib/actions/katello/content_view_version/import.rb +25 -22
  37. data/app/lib/actions/katello/content_view_version/import_library.rb +0 -1
  38. data/app/lib/actions/katello/content_view_version/import_repository.rb +21 -0
  39. data/app/lib/actions/katello/content_view_version/incremental_update.rb +85 -93
  40. data/app/lib/actions/katello/content_view_version/reset_content_view_repositories_from_metadata.rb +2 -2
  41. data/app/lib/actions/katello/organization/manifest_refresh.rb +1 -1
  42. data/app/lib/actions/katello/product/content_create.rb +10 -8
  43. data/app/lib/actions/katello/repository/destroy.rb +36 -12
  44. data/app/lib/actions/katello/repository_set/disable_repository.rb +8 -3
  45. data/app/lib/actions/pulp3/alternate_content_source/create.rb +20 -0
  46. data/app/lib/actions/pulp3/alternate_content_source/create_remote.rb +20 -0
  47. data/app/lib/actions/pulp3/alternate_content_source/delete.rb +16 -0
  48. data/app/lib/actions/pulp3/alternate_content_source/delete_remote.rb +16 -0
  49. data/app/lib/actions/pulp3/alternate_content_source/refresh.rb +23 -0
  50. data/app/lib/actions/pulp3/alternate_content_source/update.rb +16 -0
  51. data/app/lib/actions/pulp3/alternate_content_source/update_remote.rb +17 -0
  52. data/app/lib/actions/pulp3/content_view_version/{import.rb → create_import.rb} +5 -5
  53. data/app/lib/actions/pulp3/content_view_version/create_importer.rb +4 -3
  54. data/app/lib/actions/pulp3/content_view_version/destroy_importer.rb +12 -1
  55. data/app/lib/actions/pulp3/orchestration/alternate_content_source/create.rb +16 -0
  56. data/app/lib/actions/pulp3/orchestration/alternate_content_source/delete.rb +23 -0
  57. data/app/lib/actions/pulp3/orchestration/alternate_content_source/refresh.rb +15 -0
  58. data/app/lib/actions/pulp3/orchestration/alternate_content_source/update.rb +16 -0
  59. data/app/lib/actions/pulp3/orchestration/content_view_version/copy_version_units_to_library.rb +1 -1
  60. data/app/lib/actions/pulp3/orchestration/content_view_version/export_repository.rb +51 -0
  61. data/app/lib/actions/pulp3/orchestration/content_view_version/import.rb +5 -2
  62. data/app/lib/actions/pulp3/repository/save_artifact.rb +1 -1
  63. data/app/lib/katello/api/v2/error_handling.rb +1 -0
  64. data/app/lib/katello/concerns/base_template_scope_extensions.rb +24 -11
  65. data/app/lib/katello/resources/cdn/katello_cdn.rb +3 -1
  66. data/app/lib/katello/util/errata.rb +2 -3
  67. data/app/lib/katello/validators/alternate_content_source_path_validator.rb +29 -0
  68. data/app/lib/katello/validators/content_default_http_proxy_setting_validator.rb +12 -0
  69. data/app/lib/katello/validators/content_view_environment_validator.rb +10 -5
  70. data/app/models/katello/alternate_content_source.rb +71 -0
  71. data/app/models/katello/authorization/alternate_content_source.rb +33 -0
  72. data/app/models/katello/authorization/repository.rb +5 -3
  73. data/app/models/katello/candlepin/repository_mapper.rb +13 -6
  74. data/app/models/katello/cdn_configuration.rb +15 -15
  75. data/app/models/katello/concerns/content_facet_host_extensions.rb +25 -0
  76. data/app/models/katello/concerns/host_managed_extensions.rb +7 -6
  77. data/app/models/katello/concerns/http_proxy_extensions.rb +14 -0
  78. data/app/models/katello/concerns/organization_extensions.rb +4 -2
  79. data/app/models/katello/concerns/setting_extensions.rb +14 -0
  80. data/app/models/katello/concerns/smart_proxy_extensions.rb +2 -1
  81. data/app/models/katello/content.rb +1 -0
  82. data/app/models/katello/content_credential.rb +6 -0
  83. data/app/models/katello/content_override.rb +7 -3
  84. data/app/models/katello/content_view.rb +33 -2
  85. data/app/models/katello/content_view_erratum_filter.rb +26 -12
  86. data/app/models/katello/content_view_filter.rb +4 -0
  87. data/app/models/katello/content_view_version.rb +12 -0
  88. data/app/models/katello/content_view_version_export_history.rb +3 -1
  89. data/app/models/katello/erratum.rb +9 -5
  90. data/app/models/katello/events/delete_latest_content_view_version.rb +40 -0
  91. data/app/models/katello/host/content_facet.rb +14 -0
  92. data/app/models/katello/host_available_module_stream.rb +12 -0
  93. data/app/models/katello/product_content.rb +1 -0
  94. data/app/models/katello/purpose_sla_status.rb +1 -1
  95. data/app/models/katello/purpose_status.rb +2 -2
  96. data/app/models/katello/repository.rb +7 -4
  97. data/app/models/katello/root_repository.rb +1 -1
  98. data/app/models/katello/smart_proxy_alternate_content_source.rb +8 -0
  99. data/app/models/katello/sync_plan.rb +1 -1
  100. data/app/presenters/katello/product_content_presenter.rb +15 -0
  101. data/app/services/katello/applicable_host_queue.rb +1 -1
  102. data/app/services/katello/product_content_finder.rb +12 -2
  103. data/app/services/katello/pulp3/alternate_content_source.rb +123 -0
  104. data/app/services/katello/pulp3/api/file.rb +8 -0
  105. data/app/services/katello/pulp3/api/yum.rb +8 -0
  106. data/app/services/katello/pulp3/content_view_version/export.rb +27 -5
  107. data/app/services/katello/pulp3/content_view_version/import.rb +104 -71
  108. data/app/services/katello/pulp3/content_view_version/import_export_common.rb +4 -4
  109. data/app/services/katello/pulp3/content_view_version/import_gpg_keys.rb +13 -11
  110. data/app/services/katello/pulp3/content_view_version/import_validator.rb +67 -72
  111. data/app/services/katello/pulp3/content_view_version/importable_products.rb +40 -24
  112. data/app/services/katello/pulp3/content_view_version/importable_repositories.rb +102 -38
  113. data/app/services/katello/pulp3/content_view_version/metadata_generator.rb +2 -2
  114. data/app/services/katello/pulp3/content_view_version/metadata_map.rb +117 -0
  115. data/app/services/katello/pulp3/pulp_content_unit.rb +6 -1
  116. data/app/services/katello/pulp3/repository/yum.rb +70 -12
  117. data/app/services/katello/pulp3/repository.rb +6 -62
  118. data/app/services/katello/pulp3/service_common.rb +66 -0
  119. data/app/services/katello/pulp3/smart_proxy_mirror_repository.rb +4 -1
  120. data/app/services/katello/ui_notifications/content_view/delete_latest_version_failure.rb +22 -0
  121. data/app/views/foreman/job_templates/change_content_source.erb +1 -1
  122. data/app/views/foreman/job_templates/install_errata.erb +5 -5
  123. data/app/views/foreman/job_templates/install_errata_by_search_query.erb +10 -8
  124. data/app/views/foreman/job_templates/install_group.erb +4 -4
  125. data/app/views/foreman/job_templates/install_package.erb +4 -4
  126. data/app/views/foreman/job_templates/install_packages_by_search_query.erb +3 -3
  127. data/app/views/foreman/job_templates/remove_group.erb +4 -4
  128. data/app/views/foreman/job_templates/remove_package.erb +4 -4
  129. data/app/views/foreman/job_templates/remove_packages_by_search_query.erb +3 -3
  130. data/app/views/foreman/job_templates/resolve_traces.erb +2 -2
  131. data/app/views/foreman/job_templates/restart_services.erb +3 -3
  132. data/app/views/foreman/job_templates/update_group.erb +4 -4
  133. data/app/views/foreman/job_templates/update_package.erb +4 -4
  134. data/app/views/foreman/job_templates/update_packages_by_search_query.erb +3 -3
  135. data/app/views/katello/api/v2/alternate_content_sources/base.json.rabl +24 -0
  136. data/app/views/katello/api/v2/alternate_content_sources/index.json.rabl +7 -0
  137. data/app/views/katello/api/v2/alternate_content_sources/show.json.rabl +3 -0
  138. data/app/views/katello/api/v2/capsule_content/sync_status.json.rabl +1 -1
  139. data/app/views/katello/api/v2/content_facet/show.json.rabl +12 -0
  140. data/app/views/katello/api/v2/content_view_version_export_histories/show.json.rabl +2 -3
  141. data/app/views/katello/api/v2/content_view_versions/base.json.rabl +1 -1
  142. data/app/views/katello/api/v2/content_views/base.json.rabl +1 -0
  143. data/app/views/katello/api/v2/environments/show.json.rabl +2 -0
  144. data/app/views/katello/api/v2/errata/_counts.json.rabl +2 -2
  145. data/app/views/katello/api/v2/host_module_streams/base.json.rabl +2 -2
  146. data/app/views/katello/api/v2/hosts/host_collections.json.rabl +1 -1
  147. data/app/views/katello/api/v2/organizations/show.json.rabl +7 -1
  148. data/app/views/katello/api/v2/repositories/show.json.rabl +2 -1
  149. data/app/views/katello/api/v2/repository_sets/show.json.rabl +4 -0
  150. data/app/views/katello/sync_management/_repo.html.erb +8 -29
  151. data/config/routes/api/v2.rb +19 -0
  152. data/db/migrate/20150930183738_migrate_content_hosts.rb +0 -399
  153. data/db/migrate/20171025163149_remove_use_pulp_oauth_setting.rb +1 -1
  154. data/db/migrate/20171114150937_cleanup_installed_packages.rb +1 -1
  155. data/db/migrate/20180402160223_clean_up_force_post_sync_action_setting.rb +1 -1
  156. data/db/migrate/20211129200124_remove_dependency_solving_algorithm_setting.rb +1 -1
  157. data/db/migrate/20211220185935_clean_duplicate_content_units.rb +1 -1
  158. data/db/migrate/20220110223754_update_disconnected_settings.rb +5 -5
  159. data/db/migrate/20220117151612_add_alternate_content_sources.rb +48 -0
  160. data/db/migrate/20220124191056_add_type_to_cdn_configuration.rb +9 -4
  161. data/db/migrate/20220209203251_add_generated_for_to_content_views.rb +13 -0
  162. data/db/migrate/20220209205137_expand_sync_timeout_settings.rb +7 -7
  163. data/db/migrate/20220228173251_remove_drpm_from_ignorable_content.rb +12 -0
  164. data/db/migrate/20220303160220_remove_duplicate_errata.rb +1 -1
  165. data/db/migrate/20220404190836_delete_old_setting_data.rb +9 -0
  166. data/db/migrate/20220405220616_update_cdn_configuration_type.rb +11 -0
  167. data/db/migrate/20220419193414_content_settings_to_dsl_category.rb +5 -0
  168. data/db/migrate/20220428203334_add_last_refreshed_to_katello_alternate_content_sources.rb +5 -0
  169. data/db/seeds.d/110-content-view-autopublish.rb +13 -0
  170. data/db/seeds.d/150-module_job_templates.rb +1 -1
  171. data/engines/bastion/README.md +1 -0
  172. data/engines/bastion/app/assets/javascripts/bastion/components/bst-modal.directive.js +1 -0
  173. data/engines/bastion/app/views/bastion/layouts/assets.html.erb +1 -0
  174. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/activation-keys/activation-keys.routes.js +1 -1
  175. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/activation-keys/details/activation-key-details.controller.js +4 -2
  176. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/activation-keys/details/views/activation-key-details.html +1 -1
  177. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/capsule-content/capsule-content.controller.js +11 -6
  178. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/content-hosts/content/content-host-module-streams.controller.js +1 -0
  179. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/content-hosts/content/content-host-packages-installed.controller.js +1 -0
  180. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/content-hosts/content/content-host-packages.controller.js +11 -3
  181. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/content-hosts/content/content-host-traces.controller.js +1 -0
  182. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/content-hosts/content/views/content-host-packages-actions.html +1 -1
  183. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/content-hosts/content/views/content-host-packages-applicable.html +1 -1
  184. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/content-hosts/content-hosts.controller.js +8 -0
  185. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/content-hosts/details/content-host-details.controller.js +4 -2
  186. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/content-hosts/views/content-hosts.html +2 -2
  187. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/environments/content.service.js +10 -0
  188. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/environments/details/views/environment-deb-repositories.html +26 -0
  189. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/environments/details/views/environment-debs.html +27 -0
  190. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/environments/environments.controller.js +1 -0
  191. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/environments/environments.routes.js +22 -0
  192. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/environments/views/environments.html +13 -7
  193. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/i18n/bastion_katello.pot +63 -17
  194. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/products/details/repositories/details/repository-details-info.controller.js +7 -8
  195. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/products/details/repositories/details/repository-details.controller.js +10 -1
  196. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/products/details/repositories/details/views/repository-details.html +21 -3
  197. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/products/details/repositories/details/views/repository-info.html +8 -12
  198. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/products/details/repositories/new/new-repository.controller.js +7 -5
  199. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/products/details/repositories/new/views/new-repository.html +2 -1
  200. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/products/discovery/discovery-create.controller.js +1 -1
  201. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/products/discovery/views/discovery-create.html +1 -1
  202. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/products/products.routes.js +1 -0
  203. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/subscriptions/views/content-access-mode-banner.html +6 -1
  204. data/lib/katello/engine.rb +1 -5
  205. data/lib/katello/permission_creator.rb +34 -4
  206. data/lib/katello/plugin.rb +377 -3
  207. data/lib/katello/tasks/refresh_alternate_content_sources.rake +15 -0
  208. data/lib/katello/tasks/reset.rake.bak +67 -0
  209. data/lib/katello/tasks/update_content_default_http_proxy.rake +2 -3
  210. data/lib/katello/version.rb +1 -1
  211. data/locale/action_names.rb +47 -41
  212. data/locale/bn/LC_MESSAGES/katello.mo +0 -0
  213. data/locale/bn/katello.po +820 -106
  214. data/locale/bn/katello.po.time_stamp +0 -0
  215. data/locale/cs/LC_MESSAGES/katello.mo +0 -0
  216. data/locale/cs/katello.po +818 -104
  217. data/locale/cs/katello.po.time_stamp +0 -0
  218. data/locale/de/LC_MESSAGES/katello.mo +0 -0
  219. data/locale/de/katello.po +893 -179
  220. data/locale/de/katello.po.time_stamp +0 -0
  221. data/locale/en/LC_MESSAGES/katello.mo +0 -0
  222. data/locale/en/katello.po +817 -103
  223. data/locale/en/katello.po.time_stamp +0 -0
  224. data/locale/es/LC_MESSAGES/katello.mo +0 -0
  225. data/locale/es/katello.po +882 -168
  226. data/locale/es/katello.po.time_stamp +0 -0
  227. data/locale/fr/LC_MESSAGES/katello.mo +0 -0
  228. data/locale/fr/katello.po +1219 -505
  229. data/locale/fr/katello.po.time_stamp +0 -0
  230. data/locale/gu/LC_MESSAGES/katello.mo +0 -0
  231. data/locale/gu/katello.po +826 -112
  232. data/locale/gu/katello.po.time_stamp +0 -0
  233. data/locale/hi/LC_MESSAGES/katello.mo +0 -0
  234. data/locale/hi/katello.po +826 -112
  235. data/locale/hi/katello.po.time_stamp +0 -0
  236. data/locale/it/LC_MESSAGES/katello.mo +0 -0
  237. data/locale/it/katello.po +863 -148
  238. data/locale/it/katello.po.time_stamp +0 -0
  239. data/locale/ja/LC_MESSAGES/katello.mo +0 -0
  240. data/locale/ja/katello.po +1216 -499
  241. data/locale/ja/katello.po.time_stamp +0 -0
  242. data/locale/katello.pot +3847 -2507
  243. data/locale/kn/LC_MESSAGES/katello.mo +0 -0
  244. data/locale/kn/katello.po +826 -112
  245. data/locale/kn/katello.po.time_stamp +0 -0
  246. data/locale/ko/LC_MESSAGES/katello.mo +0 -0
  247. data/locale/ko/katello.po +912 -198
  248. data/locale/ko/katello.po.time_stamp +0 -0
  249. data/locale/mr/LC_MESSAGES/katello.mo +0 -0
  250. data/locale/mr/katello.po +826 -112
  251. data/locale/mr/katello.po.time_stamp +0 -0
  252. data/locale/or/LC_MESSAGES/katello.mo +0 -0
  253. data/locale/or/katello.po +826 -112
  254. data/locale/or/katello.po.time_stamp +0 -0
  255. data/locale/pa/LC_MESSAGES/katello.mo +0 -0
  256. data/locale/pa/katello.po +826 -112
  257. data/locale/pa/katello.po.time_stamp +0 -0
  258. data/locale/pt/LC_MESSAGES/katello.mo +0 -0
  259. data/locale/pt/katello.po +817 -103
  260. data/locale/pt/katello.po.time_stamp +0 -0
  261. data/locale/pt_BR/LC_MESSAGES/katello.mo +0 -0
  262. data/locale/pt_BR/katello.po +879 -165
  263. data/locale/pt_BR/katello.po.time_stamp +0 -0
  264. data/locale/ru/LC_MESSAGES/katello.mo +0 -0
  265. data/locale/ru/katello.po +927 -213
  266. data/locale/ru/katello.po.time_stamp +0 -0
  267. data/locale/ta/LC_MESSAGES/katello.mo +0 -0
  268. data/locale/ta/katello.po +820 -106
  269. data/locale/ta/katello.po.time_stamp +0 -0
  270. data/locale/te/LC_MESSAGES/katello.mo +0 -0
  271. data/locale/te/katello.po +826 -112
  272. data/locale/te/katello.po.time_stamp +0 -0
  273. data/locale/zh_CN/LC_MESSAGES/katello.mo +0 -0
  274. data/locale/zh_CN/katello.po +1202 -486
  275. data/locale/zh_CN/katello.po.time_stamp +0 -0
  276. data/locale/zh_TW/LC_MESSAGES/katello.mo +0 -0
  277. data/locale/zh_TW/katello.po +856 -142
  278. data/locale/zh_TW/katello.po.time_stamp +0 -0
  279. data/webpack/components/Bookmark/index.js +22 -14
  280. data/webpack/components/EditableTextInput/EditableTextInput.js +20 -5
  281. data/webpack/components/Errata/index.js +38 -8
  282. data/webpack/components/Packages/index.js +1 -4
  283. data/webpack/components/Search/Search.js +22 -3
  284. data/webpack/components/SelectAllCheckbox/index.js +1 -0
  285. data/webpack/components/SelectableDropdown/SelectableDropdown.js +4 -2
  286. data/webpack/components/Table/EmptyStateMessage.js +21 -7
  287. data/webpack/components/Table/MainTable.js +29 -4
  288. data/webpack/components/Table/MainTable.scss +5 -1
  289. data/webpack/components/Table/TableHooks.js +65 -20
  290. data/webpack/components/Table/TableWrapper.js +9 -3
  291. data/webpack/components/Table/components/SortableColumnHeaders.js +19 -0
  292. data/webpack/components/Table/components/TranslatedPlural.js +57 -0
  293. data/webpack/components/TypeAhead/TypeAhead.js +12 -0
  294. data/webpack/components/TypeAhead/pf4Search/TypeAheadInput.js +13 -11
  295. data/webpack/components/TypeAhead/pf4Search/TypeAheadSearch.js +7 -2
  296. data/webpack/components/extensions/HostDetails/ActionsBar/index.js +27 -0
  297. data/webpack/components/extensions/HostDetails/Cards/ContentViewDetailsCard/ChangeHostCVModal.js +250 -0
  298. data/webpack/components/extensions/HostDetails/Cards/ContentViewDetailsCard/ContentViewDetailsCard.js +232 -0
  299. data/webpack/components/extensions/HostDetails/Cards/ContentViewDetailsCard/HostContentViewActions.js +19 -0
  300. data/webpack/components/extensions/HostDetails/Cards/ContentViewDetailsCard/HostContentViewConstants.js +2 -0
  301. data/webpack/components/extensions/HostDetails/Cards/ContentViewDetailsCard/__tests__/changeHostCVModal.test.js +131 -0
  302. data/webpack/components/extensions/HostDetails/Cards/{__tests__ → ContentViewDetailsCard/__tests__}/contentViewDetailsCard.test.js +22 -0
  303. data/webpack/components/extensions/HostDetails/Cards/ContentViewDetailsCard/__tests__/contentViews.fixtures.json +443 -0
  304. data/webpack/components/extensions/HostDetails/Cards/ContentViewDetailsCard/__tests__/envPaths.fixtures.json +320 -0
  305. data/webpack/components/extensions/HostDetails/Cards/ErrataOverviewCard.js +57 -33
  306. data/webpack/components/extensions/HostDetails/Cards/ErrataOverviewCard.scss +3 -0
  307. data/webpack/components/extensions/HostDetails/Cards/HostCollectionsCard/HostCollectionsActions.js +30 -0
  308. data/webpack/components/extensions/HostDetails/Cards/HostCollectionsCard/HostCollectionsCard.js +206 -0
  309. data/webpack/components/extensions/HostDetails/Cards/HostCollectionsCard/HostCollectionsConstants.js +7 -0
  310. data/webpack/components/extensions/HostDetails/Cards/HostCollectionsCard/HostCollectionsModal.js +227 -0
  311. data/webpack/components/extensions/HostDetails/Cards/HostCollectionsCard/HostCollectionsSelectors.js +18 -0
  312. data/webpack/components/extensions/HostDetails/Cards/HostCollectionsCard/__tests__/availableHostCollections.fixtures.json +106 -0
  313. data/webpack/components/extensions/HostDetails/Cards/HostCollectionsCard/__tests__/hostCollectionsCard.test.js +118 -0
  314. data/webpack/components/extensions/HostDetails/Cards/HostCollectionsCard/__tests__/hostCollectionsModal.test.js +235 -0
  315. data/webpack/components/extensions/HostDetails/Cards/HostCollectionsCard/__tests__/removableHostCollections.fixtures.json +45 -0
  316. data/webpack/components/extensions/HostDetails/Cards/__tests__/errataOverviewCard.test.js +33 -8
  317. data/webpack/components/extensions/HostDetails/DetailsTabCards/InstalledProductsCard.js +44 -0
  318. data/webpack/components/extensions/HostDetails/DetailsTabCards/RecentCommunicationCardExtensions.js +37 -0
  319. data/webpack/components/extensions/HostDetails/DetailsTabCards/RegistrationCard.js +107 -0
  320. data/webpack/components/extensions/HostDetails/DetailsTabCards/SystemPropertiesCardExtensions.js +38 -0
  321. data/webpack/components/extensions/HostDetails/HostDetailsActions.js +11 -0
  322. data/webpack/components/extensions/HostDetails/Tabs/ContentTab/SecondaryTabsRoutes.js +4 -0
  323. data/webpack/components/extensions/HostDetails/Tabs/ContentTab/constants.js +2 -0
  324. data/webpack/components/extensions/HostDetails/Tabs/ContentTab/index.js +6 -1
  325. data/webpack/components/extensions/HostDetails/Tabs/ErrataTab/ErrataTab.js +176 -72
  326. data/webpack/components/extensions/HostDetails/Tabs/ErrataTab/HostErrataActions.js +1 -7
  327. data/webpack/components/extensions/HostDetails/Tabs/ModuleStreamsTab/ModuleStreamsActions.js +1 -3
  328. data/webpack/components/extensions/HostDetails/Tabs/ModuleStreamsTab/ModuleStreamsConstants.js +28 -0
  329. data/webpack/components/extensions/HostDetails/Tabs/ModuleStreamsTab/ModuleStreamsTab.js +522 -118
  330. data/webpack/components/extensions/HostDetails/Tabs/PackagesTab/HostPackagesActions.js +1 -7
  331. data/webpack/components/extensions/HostDetails/Tabs/PackagesTab/PackageInstallModal.js +6 -4
  332. data/webpack/components/extensions/HostDetails/Tabs/PackagesTab/PackagesTab.js +164 -58
  333. data/webpack/components/extensions/HostDetails/Tabs/RemoteExecutionActions.js +59 -49
  334. data/webpack/components/extensions/HostDetails/Tabs/RemoteExecutionConstants.js +1 -0
  335. data/webpack/components/extensions/HostDetails/Tabs/RemoteExecutionHooks.js +85 -0
  336. data/webpack/components/extensions/HostDetails/Tabs/RepositorySetsTab/RepositorySetsActions.js +33 -54
  337. data/webpack/components/extensions/HostDetails/Tabs/RepositorySetsTab/RepositorySetsConstants.js +20 -0
  338. data/webpack/components/extensions/HostDetails/Tabs/RepositorySetsTab/RepositorySetsTab.js +298 -107
  339. data/webpack/components/extensions/HostDetails/Tabs/TracesTab/EnableTracerModal.js +14 -7
  340. data/webpack/components/extensions/HostDetails/Tabs/TracesTab/HostTracesActions.js +2 -1
  341. data/webpack/components/extensions/HostDetails/Tabs/TracesTab/TracesEnabler.js +104 -0
  342. data/webpack/components/extensions/HostDetails/Tabs/TracesTab/TracesTab.js +134 -57
  343. data/webpack/components/extensions/HostDetails/Tabs/__tests__/errataTab.test.js +37 -32
  344. data/webpack/components/extensions/HostDetails/Tabs/{ModuleStreamsTab/__tests__/modules.fixtures.json → __tests__/moduleStreams.fixtures.json} +6 -3
  345. data/webpack/components/extensions/HostDetails/Tabs/__tests__/moduleStreamsTab.test.js +261 -0
  346. data/webpack/components/extensions/HostDetails/Tabs/__tests__/packageInstallModal.test.js +21 -15
  347. data/webpack/components/extensions/HostDetails/Tabs/__tests__/packagesTab.test.js +44 -1
  348. data/webpack/components/extensions/HostDetails/Tabs/__tests__/repositorySets.fixtures.json +4 -1
  349. data/webpack/components/extensions/HostDetails/Tabs/__tests__/repositorySetsTab.test.js +105 -6
  350. data/webpack/components/extensions/HostDetails/Tabs/__tests__/tracesTab.test.js +25 -6
  351. data/webpack/components/extensions/HostDetails/Tabs/customizedRexUrlHelpers.js +6 -0
  352. data/webpack/components/extensions/HostDetails/hostDetailsHelpers.js +18 -0
  353. data/webpack/containers/Application/config.js +5 -0
  354. data/webpack/global_index.js +32 -9
  355. data/webpack/global_test_setup.js +13 -0
  356. data/webpack/redux/actions/RedHatRepositories/enabled.js +2 -1
  357. data/webpack/redux/actions/RedHatRepositories/helpers.js +13 -8
  358. data/webpack/scenes/AlternateContentSources/ACSActions.js +65 -0
  359. data/webpack/scenes/AlternateContentSources/ACSConstants.js +18 -0
  360. data/webpack/scenes/AlternateContentSources/ACSIndexPage.js +23 -0
  361. data/webpack/scenes/AlternateContentSources/ACSSelectors.js +24 -0
  362. data/webpack/scenes/AlternateContentSources/Create/ACSCreateContext.js +4 -0
  363. data/webpack/scenes/AlternateContentSources/Create/ACSCreateWizard.js +160 -0
  364. data/webpack/scenes/AlternateContentSources/Create/Steps/ACSCreateFinish.js +79 -0
  365. data/webpack/scenes/AlternateContentSources/Create/Steps/ACSCredentials.js +199 -0
  366. data/webpack/scenes/AlternateContentSources/Create/Steps/ACSReview.js +104 -0
  367. data/webpack/scenes/AlternateContentSources/Create/Steps/ACSSmartProxies.js +41 -0
  368. data/webpack/scenes/AlternateContentSources/Create/Steps/AcsUrlPaths.js +71 -0
  369. data/webpack/scenes/AlternateContentSources/Create/Steps/NameACS.js +57 -0
  370. data/webpack/scenes/AlternateContentSources/Create/Steps/SelectSource.js +77 -0
  371. data/webpack/scenes/AlternateContentSources/Create/__tests__/acsCreate.test.js +149 -0
  372. data/webpack/scenes/AlternateContentSources/Create/__tests__/acsCreateData.fixtures.json +3 -0
  373. data/webpack/scenes/AlternateContentSources/Create/__tests__/contentCredentials.fixtures.json +69 -0
  374. data/webpack/scenes/AlternateContentSources/Create/__tests__/smartProxy.fixtures.json +65 -0
  375. data/webpack/scenes/AlternateContentSources/MainTable/ACSTable.js +162 -0
  376. data/webpack/scenes/AlternateContentSources/MainTable/__tests__/acsIndex.fixtures.json +91 -0
  377. data/webpack/scenes/AlternateContentSources/MainTable/__tests__/acsTable.test.js +67 -0
  378. data/webpack/scenes/AlternateContentSources/index.js +4 -0
  379. data/webpack/scenes/Content/Details/ContentRepositories.js +1 -0
  380. data/webpack/scenes/Content/Table/ContentTable.js +1 -0
  381. data/webpack/scenes/ContentCredentials/ContentCredentialSelectors.js +4 -1
  382. data/webpack/scenes/ContentViews/ContentViewsActions.js +6 -2
  383. data/webpack/scenes/ContentViews/ContentViewsConstants.js +11 -3
  384. data/webpack/scenes/ContentViews/Copy/CopyContentViewForm.js +2 -1
  385. data/webpack/scenes/ContentViews/Create/ContentViewFormComponents.js +10 -1
  386. data/webpack/scenes/ContentViews/Create/CreateContentViewForm.js +2 -1
  387. data/webpack/scenes/ContentViews/Delete/ContentViewDeleteWizard.js +7 -5
  388. data/webpack/scenes/ContentViews/Delete/Steps/CVDeletionFinish.js +29 -21
  389. data/webpack/scenes/ContentViews/Delete/__tests__/contentViewDelete.test.js +15 -8
  390. data/webpack/scenes/ContentViews/Details/ComponentContentViews/ComponentContentViewAddModal.js +2 -2
  391. data/webpack/scenes/ContentViews/Details/ComponentContentViews/ComponentContentViewBulkAddModal.js +2 -2
  392. data/webpack/scenes/ContentViews/Details/ComponentContentViews/ContentViewComponents.js +3 -1
  393. data/webpack/scenes/ContentViews/Details/ContentViewDetailActions.js +34 -8
  394. data/webpack/scenes/ContentViews/Details/ContentViewDetailSelectors.js +33 -29
  395. data/webpack/scenes/ContentViews/Details/ContentViewDetails.js +130 -79
  396. data/webpack/scenes/ContentViews/Details/ContentViewInfo.js +16 -2
  397. data/webpack/scenes/ContentViews/Details/Filters/Add/CVFilterAddModal.js +2 -1
  398. data/webpack/scenes/ContentViews/Details/Filters/AffectedRepositories/AffectedRepositoryTable.js +2 -1
  399. data/webpack/scenes/ContentViews/Details/Filters/CVContainerImageFilterContent.js +6 -1
  400. data/webpack/scenes/ContentViews/Details/Filters/CVErrataDateFilterContent.js +41 -21
  401. data/webpack/scenes/ContentViews/Details/Filters/CVErrataIDFilterContent.js +38 -20
  402. data/webpack/scenes/ContentViews/Details/Filters/CVModuleStreamFilterContent.js +2 -0
  403. data/webpack/scenes/ContentViews/Details/Filters/CVPackageGroupFilterContent.js +8 -1
  404. data/webpack/scenes/ContentViews/Details/Filters/CVRpmFilterContent.js +9 -1
  405. data/webpack/scenes/ContentViews/Details/Filters/ContentViewFilters.js +2 -1
  406. data/webpack/scenes/ContentViews/Details/Filters/MatchContentModal/CVRpmMatchContentModal.js +1 -0
  407. data/webpack/scenes/ContentViews/Details/Filters/Rules/ContainerTag/AddEditContainerTagRuleModal.js +27 -12
  408. data/webpack/scenes/ContentViews/Details/Filters/Rules/Package/AddEditPackageRuleModal.js +39 -17
  409. data/webpack/scenes/ContentViews/Details/Filters/__tests__/CVContainerImageFilterContent.test.js +27 -10
  410. data/webpack/scenes/ContentViews/Details/Filters/__tests__/CVRpmFilterContent.test.js +46 -23
  411. data/webpack/scenes/ContentViews/Details/Histories/ContentViewHistories.js +3 -2
  412. data/webpack/scenes/ContentViews/Details/Promote/ContentViewVersionPromote.js +5 -2
  413. data/webpack/scenes/ContentViews/Details/Repositories/ContentViewRepositories.js +161 -108
  414. data/webpack/scenes/ContentViews/Details/Repositories/__tests__/contentViewAddRemove.test.js +7 -7
  415. data/webpack/scenes/ContentViews/Details/Repositories/__tests__/contentViewRepoAdd.fixture.json +1 -0
  416. data/webpack/scenes/ContentViews/Details/Versions/BulkDelete/ActionSummary.js +58 -0
  417. data/webpack/scenes/ContentViews/Details/Versions/BulkDelete/BulkDeleteContextWrapper.js +45 -0
  418. data/webpack/scenes/ContentViews/Details/Versions/BulkDelete/BulkDeleteHelpers.js +30 -0
  419. data/webpack/scenes/ContentViews/Details/Versions/BulkDelete/BulkDeleteModal.js +56 -0
  420. data/webpack/scenes/ContentViews/Details/Versions/BulkDelete/Steps/ConfirmBulkDelete.js +126 -0
  421. data/webpack/scenes/ContentViews/Details/Versions/BulkDelete/Steps/FinishBulkDelete.js +61 -0
  422. data/webpack/scenes/ContentViews/Details/Versions/BulkDelete/Steps/ReassignActivationKeys.js +196 -0
  423. data/webpack/scenes/ContentViews/Details/Versions/BulkDelete/Steps/ReassignHosts.js +220 -0
  424. data/webpack/scenes/ContentViews/Details/Versions/BulkDelete/Steps/ReviewEnvironments.js +104 -0
  425. data/webpack/scenes/ContentViews/Details/Versions/BulkDelete/__tests__/BulkDeleteModal.test.js +122 -0
  426. data/webpack/scenes/ContentViews/Details/Versions/BulkDelete/__tests__/BulkDeleteVersions.fixtures.json +600 -0
  427. data/webpack/scenes/ContentViews/Details/Versions/BulkDelete/__tests__/contentView.fixtures.json +1504 -0
  428. data/webpack/scenes/ContentViews/Details/Versions/BulkDelete/__tests__/contentViewVersion.fixtures.json +936 -0
  429. data/webpack/scenes/ContentViews/Details/Versions/BulkDelete/__tests__/environmentPaths.fixtures.json +261 -0
  430. data/webpack/scenes/ContentViews/Details/Versions/BulkDelete/__tests__/hosts.fixtures.json +163 -0
  431. data/webpack/scenes/ContentViews/Details/Versions/BulkDelete/bulkDeleteSteps.js +79 -0
  432. data/webpack/scenes/ContentViews/Details/Versions/ContentViewVersions.js +192 -167
  433. data/webpack/scenes/ContentViews/Details/Versions/Delete/RemoveCVVersionWizard.js +2 -5
  434. data/webpack/scenes/ContentViews/Details/Versions/Delete/RemoveSteps/CVVersionDeleteFinish.js +38 -53
  435. data/webpack/scenes/ContentViews/Details/Versions/Delete/RemoveSteps/CVVersionRemoveReview.js +1 -1
  436. data/webpack/scenes/ContentViews/Details/Versions/Delete/__tests__/cvVersionRemove.test.js +6 -12
  437. data/webpack/scenes/ContentViews/Details/Versions/Delete/affectedActivationKeys.js +1 -0
  438. data/webpack/scenes/ContentViews/Details/Versions/Delete/affectedHosts.js +1 -0
  439. data/webpack/scenes/ContentViews/Details/Versions/VersionDetails/ContentViewVersionDetailConfig.js +1 -0
  440. data/webpack/scenes/ContentViews/Details/Versions/VersionDetails/ContentViewVersionDetails.js +8 -20
  441. data/webpack/scenes/ContentViews/Details/Versions/VersionDetails/ContentViewVersionDetailsHeader.js +23 -13
  442. data/webpack/scenes/ContentViews/Details/Versions/VersionDetails/ContentViewVersionDetailsTable.js +3 -0
  443. data/webpack/scenes/ContentViews/Details/Versions/VersionDetails/__tests__/ContentViewVersionDetails.fixtures.json +4 -4
  444. data/webpack/scenes/ContentViews/Details/Versions/VersionDetails/__tests__/ContentViewVersionDetails.test.js +0 -3
  445. data/webpack/scenes/ContentViews/Details/Versions/VersionDetails/__tests__/ContentViewVersionDetailsEmpty.test.js +4 -4
  446. data/webpack/scenes/ContentViews/Details/Versions/__tests__/contentViewVersions.test.js +12 -14
  447. data/webpack/scenes/ContentViews/Details/__tests__/contentViewDetails.fixtures.json +1 -0
  448. data/webpack/scenes/ContentViews/Publish/CVPublishFinish.js +96 -117
  449. data/webpack/scenes/ContentViews/Publish/PublishContentViewWizard.js +13 -19
  450. data/webpack/scenes/ContentViews/Publish/__tests__/publishContentView.test.js +9 -20
  451. data/webpack/scenes/ContentViews/Table/ContentViewsTable.js +165 -148
  452. data/webpack/scenes/ContentViews/Table/tableDataGenerator.js +2 -0
  453. data/webpack/scenes/ContentViews/components/ContentViewIcon.js +14 -3
  454. data/webpack/scenes/ContentViews/components/EnvironmentLabels.js +4 -3
  455. data/webpack/scenes/ContentViews/components/EnvironmentPaths/EnvironmentPaths.js +10 -6
  456. data/webpack/scenes/ContentViews/components/EnvironmentPaths/EnvironmentPaths.scss +6 -1
  457. data/webpack/scenes/ContentViews/components/TaskPresenter/TaskPresenter.js +40 -35
  458. data/webpack/scenes/ContentViews/expansions/RelatedCompositeContentViewsModal.js +1 -1
  459. data/webpack/scenes/ContentViews/expansions/RelatedContentViewComponentsModal.js +2 -2
  460. data/webpack/scenes/ContentViews/helpers.js +3 -0
  461. data/webpack/scenes/Hosts/ChangeContentSource/helpers.js +5 -0
  462. data/webpack/scenes/RedHatRepositories/RedHatRepositoriesPage.js +3 -3
  463. data/webpack/scenes/RedHatRepositories/components/EnabledRepository/EnabledRepository.js +2 -1
  464. data/webpack/scenes/RedHatRepositories/components/EnabledRepository/__tests__/EnabledRepository.test.js +2 -0
  465. data/webpack/scenes/RedHatRepositories/components/Search.js +4 -4
  466. data/webpack/scenes/SmartProxy/SmartProxyContentActions.js +9 -2
  467. data/webpack/scenes/SmartProxy/SmartProxyContentConstants.js +1 -1
  468. data/webpack/scenes/SmartProxy/SmartProxyContentSelectors.js +10 -1
  469. data/webpack/scenes/Subscriptions/Manifest/CdnConfigurationTab/CdnConfigurationConstants.js +3 -3
  470. data/webpack/scenes/Subscriptions/Manifest/CdnConfigurationTab/CdnTypeForm.js +2 -0
  471. data/webpack/scenes/Subscriptions/Manifest/CdnConfigurationTab/{AirGappedTypeForm.js → ExportSyncForm.js} +7 -6
  472. data/webpack/scenes/Subscriptions/Manifest/CdnConfigurationTab/{UpstreamServerTypeForm.js → NetworkSyncForm.js} +15 -7
  473. data/webpack/scenes/Subscriptions/Manifest/CdnConfigurationTab/__tests__/{AirGappedTypeForm.test.js → ExportSyncForm.test.js} +4 -4
  474. data/webpack/scenes/Subscriptions/Manifest/CdnConfigurationTab/__tests__/{UpstreamServerTypeForm.test.js → NetworkSyncForm.test.js} +8 -8
  475. data/webpack/scenes/Subscriptions/Manifest/CdnConfigurationTab/index.js +11 -11
  476. data/webpack/scenes/Subscriptions/SubscriptionConstants.js +1 -0
  477. data/webpack/scenes/Subscriptions/SubscriptionsPage.js +8 -7
  478. data/webpack/scenes/Tasks/TaskActions.js +6 -0
  479. data/webpack/scenes/Tasks/TaskSelectors.js +11 -0
  480. data/webpack/scenes/Tasks/helpers.js +60 -5
  481. data/webpack/utils/helpers.js +2 -0
  482. metadata +183 -38
  483. data/app/models/setting/content.rb +0 -201
  484. data/db/seeds.d/107-enable_dynflow.rb +0 -8
  485. data/webpack/components/extensions/HostDetails/Cards/ContentViewDetailsCard.js +0 -96
  486. data/webpack/components/extensions/HostDetails/Tabs/ModuleStreamsTab/__tests__/moduleStreamsTab.test.js +0 -108
  487. data/webpack/components/extensions/HostDetails/Tabs/TracesTab/EnableTracerEmptyState.js +0 -42
  488. data/webpack/scenes/ContentViews/Details/DetailsContainer.js +0 -36
@@ -4,7 +4,7 @@ import { Route } from 'react-router-dom';
4
4
 
5
5
  import ContentViewFilterDetails from '../ContentViewFilterDetails';
6
6
  import { cvFilterDetailsKey } from '../../../ContentViewsConstants';
7
- import nock, {
7
+ import {
8
8
  nockInstance,
9
9
  assertNockRequest,
10
10
  mockAutocomplete,
@@ -22,6 +22,8 @@ const cvFilterEditDeletePath = api.getApiUrl('/content_view_filters/2/rules/2');
22
22
  const cvPackageFilterRulesPath = api.getApiUrl('/content_view_filters/2/rules');
23
23
  const cvPackageFilterRuleCreatePath = api.getApiUrl('/content_view_filters/2/rules');
24
24
  const autocompleteUrl = '/content_view_filters/2/rules/auto_complete_search';
25
+ const autocompleteNameUrl = '/packages/auto_complete_name';
26
+ const autocompleteArchUrl = '/packages/auto_complete_arch';
25
27
  const renderOptions = {
26
28
  apiNamespace: cvFilterDetailsKey(1, 2),
27
29
  routerParams: {
@@ -32,21 +34,10 @@ const renderOptions = {
32
34
 
33
35
  const withCVRoute = component => <Route path="/content_views/:id([0-9]+)#/filters/:filterId([0-9]+)">{component}</Route>;
34
36
 
35
- let searchDelayScope;
36
- let autoSearchScope;
37
- beforeEach(() => {
38
- searchDelayScope = mockSetting(nockInstance, 'autosearch_delay', 0);
39
- autoSearchScope = mockSetting(nockInstance, 'autosearch_while_typing');
40
- });
41
-
42
- afterEach(() => {
43
- assertNockRequest(searchDelayScope);
44
- assertNockRequest(autoSearchScope);
45
- nock.cleanAll();
46
- });
47
-
48
37
  test('Can show filter details and package groups on page load', async (done) => {
49
38
  const { name: cvFilterName } = cvFilterDetails;
39
+ const searchDelayScope = mockSetting(nockInstance, 'autosearch_delay', 0);
40
+ const autoSearchScope = mockSetting(nockInstance, 'autosearch_while_typing');
50
41
  const cvFilterScope = nockInstance
51
42
  .get(cvFilterDetailsPath)
52
43
  .query(true)
@@ -74,6 +65,8 @@ test('Can show filter details and package groups on page load', async (done) =>
74
65
  });
75
66
 
76
67
  assertNockRequest(autocompleteScope);
68
+ assertNockRequest(searchDelayScope);
69
+ assertNockRequest(autoSearchScope);
77
70
  assertNockRequest(cvFilterScope);
78
71
  assertNockRequest(cvFiltersScope);
79
72
  assertNockRequest(cvPackageFilterRulesScope, done);
@@ -88,6 +81,8 @@ test('Can search for package rules in package filter details', async (done) => {
88
81
  const { name: lastPackageRuleName } = lastPackageRule;
89
82
  const searchQueryMatcher = actualParams =>
90
83
  actualParams?.search?.includes(lastPackageRuleName);
84
+ const searchDelayScope = mockSetting(nockInstance, 'autosearch_delay', 0);
85
+ const autoSearchScope = mockSetting(nockInstance, 'autosearch_while_typing');
91
86
 
92
87
  const cvFilterScope = nockInstance
93
88
  .get(cvFilterDetailsPath)
@@ -127,6 +122,8 @@ test('Can search for package rules in package filter details', async (done) => {
127
122
  });
128
123
 
129
124
  assertNockRequest(autocompleteScope);
125
+ assertNockRequest(searchDelayScope);
126
+ assertNockRequest(autoSearchScope);
130
127
  assertNockRequest(cvFilterScope);
131
128
  assertNockRequest(cvFiltersScope);
132
129
  assertNockRequest(cvPackageFilterRulesScope);
@@ -136,6 +133,12 @@ test('Can search for package rules in package filter details', async (done) => {
136
133
 
137
134
  test('Can add package rules to filter in a self-closing modal', async (done) => {
138
135
  const { name: cvFilterName } = cvFilterDetails;
136
+ const autocompleteScope = mockAutocomplete(nockInstance, autocompleteUrl);
137
+ const autocompleteNameScope = mockAutocomplete(nockInstance, autocompleteNameUrl);
138
+ const autocompleteArchScope = mockAutocomplete(nockInstance, autocompleteArchUrl);
139
+ const searchDelayScope = mockSetting(nockInstance, 'autosearch_delay', 0, 3);
140
+ const autoSearchScope = mockSetting(nockInstance, 'autosearch_while_typing', undefined, 3);
141
+
139
142
  const cvFiltersScope = nockInstance
140
143
  .get(cvFiltersPath)
141
144
  .query(true)
@@ -154,6 +157,7 @@ test('Can add package rules to filter in a self-closing modal', async (done) =>
154
157
  architecture: 'noarch',
155
158
  name: 'elephant',
156
159
  };
160
+
157
161
  const createdFilterDetails = {
158
162
  architecture: 'noarch',
159
163
  content_view_filter_id: 1,
@@ -167,9 +171,9 @@ test('Can add package rules to filter in a self-closing modal', async (done) =>
167
171
  .post(cvPackageFilterRuleCreatePath, newFilterRuleDetails)
168
172
  .reply(201, createdFilterDetails);
169
173
 
170
- const autocompleteScope = mockAutocomplete(nockInstance, autocompleteUrl);
171
-
172
- const { getByText, queryByText, getByLabelText } =
174
+ const {
175
+ getByText, queryByText, getByLabelText, getAllByLabelText,
176
+ } =
173
177
  renderWithRedux(withCVRoute(<ContentViewFilterDetails
174
178
  cvId={1}
175
179
  details={details}
@@ -183,19 +187,22 @@ test('Can add package rules to filter in a self-closing modal', async (done) =>
183
187
  });
184
188
  getByLabelText('add_rpm_rule').click();
185
189
  await patientlyWaitFor(() => {
186
- expect(getByLabelText('input_name')).toBeInTheDocument();
187
- expect(getByLabelText('input_architecture')).toBeInTheDocument();
190
+ expect(getAllByLabelText('text input for search')[1]).toBeInTheDocument();
191
+ expect(getAllByLabelText('text input for search')[2]).toBeInTheDocument();
188
192
  expect(getByLabelText('add_package_filter_rule')).toBeInTheDocument();
189
193
  });
190
-
191
- fireEvent.change(getByLabelText('input_name'), { target: { value: 'elephant' } });
192
- fireEvent.change(getByLabelText('input_architecture'), { target: { value: 'noarch' } });
194
+ fireEvent.change(getAllByLabelText('text input for search')[1], { target: { value: 'elephant' } });
195
+ fireEvent.change(getAllByLabelText('text input for search')[2], { target: { value: 'noarch' } });
193
196
  fireEvent.submit(getByLabelText('add_package_filter_rule'));
194
197
 
195
198
  await patientlyWaitFor(() => {
196
199
  expect(queryByText('Add rule')).not.toBeInTheDocument();
197
200
  });
198
201
  assertNockRequest(autocompleteScope);
202
+ assertNockRequest(searchDelayScope);
203
+ assertNockRequest(autoSearchScope);
204
+ assertNockRequest(autocompleteNameScope);
205
+ assertNockRequest(autocompleteArchScope);
199
206
  assertNockRequest(cvFiltersScope);
200
207
  assertNockRequest(cvFilterDetailsScope);
201
208
  assertNockRequest(cvPackageFilterRulesScope);
@@ -206,6 +213,9 @@ test('Can add package rules to filter in a self-closing modal', async (done) =>
206
213
  test('Remove rpm filter rule in a self-closing modal', async (done) => {
207
214
  const { name: cvFilterName } = cvFilterDetails;
208
215
  const autocompleteScope = mockAutocomplete(nockInstance, autocompleteUrl);
216
+ const searchDelayScope = mockSetting(nockInstance, 'autosearch_delay', 0);
217
+ const autoSearchScope = mockSetting(nockInstance, 'autosearch_while_typing');
218
+
209
219
  const cvFiltersScope = nockInstance
210
220
  .get(cvFiltersPath)
211
221
  .query(true)
@@ -247,6 +257,8 @@ test('Remove rpm filter rule in a self-closing modal', async (done) => {
247
257
  getByText('Remove').click();
248
258
 
249
259
  assertNockRequest(autocompleteScope);
260
+ assertNockRequest(searchDelayScope);
261
+ assertNockRequest(autoSearchScope);
250
262
  assertNockRequest(cvFiltersScope);
251
263
  assertNockRequest(cvFilterDetailsScope);
252
264
  assertNockRequest(cvPackageFilterRulesScope);
@@ -256,13 +268,19 @@ test('Remove rpm filter rule in a self-closing modal', async (done) => {
256
268
 
257
269
  test('Edit rpm filter rule in a self-closing modal', async (done) => {
258
270
  const { name: cvFilterName } = cvFilterDetails;
259
- const autocompleteScope = mockAutocomplete(nockInstance, autocompleteUrl);
271
+ const autocompleteScope = mockAutocomplete(nockInstance, autocompleteUrl, true, undefined, 2);
272
+ const autocompleteNameScope = mockAutocomplete(nockInstance, autocompleteNameUrl);
273
+ const autocompleteArchScope = mockAutocomplete(nockInstance, autocompleteArchUrl);
274
+ const searchDelayScope = mockSetting(nockInstance, 'autosearch_delay', 0, 3);
275
+ const autoSearchScope = mockSetting(nockInstance, 'autosearch_while_typing', undefined, 3);
260
276
  const cvFiltersScope = nockInstance
261
277
  .get(cvFiltersPath)
278
+ .times(2)
262
279
  .query(true)
263
280
  .reply(200, cvFilterFixtures);
264
281
  const cvFilterDetailsScope = nockInstance
265
282
  .get(cvFilterDetailsPath)
283
+ .times(2)
266
284
  .query(true)
267
285
  .reply(200, cvFilterDetails);
268
286
  const cvPackageFilterRulesScope = nockInstance
@@ -309,8 +327,13 @@ test('Edit rpm filter rule in a self-closing modal', async (done) => {
309
327
  });
310
328
 
311
329
  assertNockRequest(autocompleteScope);
330
+ assertNockRequest(searchDelayScope);
331
+ assertNockRequest(autoSearchScope);
332
+ assertNockRequest(autocompleteNameScope);
333
+ assertNockRequest(autocompleteArchScope);
312
334
  assertNockRequest(cvFiltersScope);
313
335
  assertNockRequest(cvFilterDetailsScope);
314
336
  assertNockRequest(cvPackageFilterRulesScope);
315
337
  assertNockRequest(editScope, done);
338
+ act(done);
316
339
  });
@@ -49,9 +49,9 @@ const ContentViewHistories = ({ cvId }) => {
49
49
  const taskType = task ? task.label : taskTypes[action];
50
50
 
51
51
  if (taskType === taskTypes.removal) {
52
- return <>{__('Deleted from ')} <Label isTruncated key="1" color="blue" href={`/lifecycle_environments/${environment?.id}`}>{`${environment?.name ?? __('all environments')}`}</Label>{}</>;
52
+ return <>{__('Deleted from ')} <Label isTruncated key="1" color="blue" href={`/lifecycle_environments/${environment?.id}`}>{`${environment?.name ?? __('all environments')}`}</Label></>;
53
53
  } else if (action === 'promotion' || taskType === taskTypes.promotion) {
54
- return <>{__('Promoted to ')}<Label isTruncated key="2" color="blue" href={`/lifecycle_environments/${environment?.id}`}>{`${environment?.name}`}</Label>{}</>;
54
+ return <>{__('Promoted to ')}<Label isTruncated key="2" color="blue" href={`/lifecycle_environments/${environment?.id}`}>{`${environment?.name}`}</Label></>;
55
55
  } else if (taskType === taskTypes.publish) {
56
56
  return __('Published new version');
57
57
  } else if (taskType === taskTypes.export) {
@@ -81,6 +81,7 @@ const ContentViewHistories = ({ cvId }) => {
81
81
  error,
82
82
  status,
83
83
  }}
84
+ ouiaId="content-view-history-table"
84
85
  variant={TableVariant.compact}
85
86
  autocompleteEndpoint={`/content_views/${cvId}/history/auto_complete_search`}
86
87
  fetchItems={useCallback(params => getContentViewHistories(cvId, params), [cvId])}
@@ -21,6 +21,7 @@ import {
21
21
  } from './ContentViewVersionPromoteSelectors';
22
22
  import ComponentEnvironments from '../ComponentContentViews/ComponentEnvironments';
23
23
  import Loading from '../../../../components/Loading';
24
+ import getContentViews from '../../ContentViewsActions';
24
25
 
25
26
  const ContentViewVersionPromote = ({
26
27
  cvId, versionIdToPromote, versionNameToPromote,
@@ -52,7 +53,7 @@ const ContentViewVersionPromote = ({
52
53
  versionEnvironments,
53
54
  environment_ids: userCheckedItems.map(item => item.id),
54
55
  force: true,
55
- }));
56
+ }, () => dispatch(getContentViews())));
56
57
  };
57
58
 
58
59
  useDeepCompareEffect(() => {
@@ -66,6 +67,7 @@ const ContentViewVersionPromote = ({
66
67
  }
67
68
  if (promoteError) {
68
69
  setLoading(false);
70
+ setIsOpen(false);
69
71
  }
70
72
  }, [promoteResponse, promoteResolved, promoteError, detailsPage,
71
73
  setRedirect, setLoading, setIsOpen, dispatch, cvId]);
@@ -157,6 +159,7 @@ const ContentViewVersionPromote = ({
157
159
  />
158
160
  <ActionGroup style={{ margin: 0 }}>
159
161
  <Button
162
+ ouiaId="cv-version-promote-submit"
160
163
  aria-label="promote_content_view"
161
164
  variant="primary"
162
165
  isDisabled={submitDisabled}
@@ -164,7 +167,7 @@ const ContentViewVersionPromote = ({
164
167
  >
165
168
  {__('Promote')}
166
169
  </Button>
167
- <Button variant="link" onClick={() => setIsOpen(false)}>
170
+ <Button ouiaId="cv-version-promote-cancel" variant="link" onClick={() => setIsOpen(false)}>
168
171
  {__('Cancel')}
169
172
  </Button>
170
173
  </ActionGroup>
@@ -1,41 +1,69 @@
1
- import React, { useState, useEffect, useCallback } from 'react';
1
+ import React, {
2
+ useCallback,
3
+ useEffect,
4
+ useState,
5
+ } from 'react';
6
+
7
+ import { translate as __ } from 'foremanReact/common/I18n';
8
+ import { urlBuilder } from 'foremanReact/common/urlHelpers';
9
+ import { STATUS } from 'foremanReact/constants';
10
+ import {
11
+ lowerCase,
12
+ upperFirst,
13
+ } from 'lodash';
14
+ import PropTypes from 'prop-types';
15
+ import {
16
+ shallowEqual,
17
+ useDispatch,
18
+ useSelector,
19
+ } from 'react-redux';
2
20
  import useDeepCompareEffect from 'use-deep-compare-effect';
3
- import { lowerCase, upperFirst } from 'lodash';
4
- import { useSelector, shallowEqual, useDispatch } from 'react-redux';
21
+
5
22
  import {
6
- Bullseye,
7
- Split,
8
- SplitItem,
9
- Button,
10
23
  ActionList,
11
24
  ActionListItem,
25
+ Bullseye,
26
+ Button,
12
27
  Dropdown,
13
28
  DropdownItem,
14
29
  KebabToggle,
30
+ Split,
31
+ SplitItem,
32
+ Checkbox,
15
33
  } from '@patternfly/react-core';
16
- import { TableVariant, fitContent } from '@patternfly/react-table';
17
- import { STATUS } from 'foremanReact/constants';
18
- import { translate as __ } from 'foremanReact/common/I18n';
19
- import { urlBuilder } from 'foremanReact/common/urlHelpers';
20
- import PropTypes from 'prop-types';
21
-
34
+ import {
35
+ TableVariant,
36
+ Thead,
37
+ Tbody,
38
+ Tr,
39
+ Th,
40
+ Td,
41
+ } from '@patternfly/react-table';
42
+ import AddedStatusLabel from '../../../../components/AddedStatusLabel';
43
+ import SelectableDropdown from '../../../../components/SelectableDropdown';
22
44
  import TableWrapper from '../../../../components/Table/TableWrapper';
23
- import onSelect from '../../../../components/Table/helpers';
24
- import { getContentViewRepositories, getRepositoryTypes, updateContentView } from '../ContentViewDetailActions';
45
+ import {
46
+ ADDED,
47
+ ALL_STATUSES,
48
+ NOT_ADDED,
49
+ } from '../../ContentViewsConstants';
50
+ import { hasPermission } from '../../helpers';
51
+ import {
52
+ getContentViewRepositories,
53
+ getRepositoryTypes,
54
+ updateContentView,
55
+ } from '../ContentViewDetailActions';
25
56
  import {
26
57
  selectCVRepos,
27
- selectCVReposStatus,
28
58
  selectCVReposError,
59
+ selectCVReposStatus,
29
60
  selectRepoTypes,
30
61
  selectRepoTypesStatus,
31
62
  } from '../ContentViewDetailSelectors';
32
- import { ADDED, NOT_ADDED, ALL_STATUSES } from '../../ContentViewsConstants';
33
63
  import ContentCounts from './ContentCounts';
34
64
  import LastSync from './LastSync';
35
65
  import RepoIcon from './RepoIcon';
36
- import AddedStatusLabel from '../../../../components/AddedStatusLabel';
37
- import SelectableDropdown from '../../../../components/SelectableDropdown';
38
- import { hasPermission } from '../../helpers';
66
+ import { useSelectionSet } from '../../../../components/Table/TableHooks';
39
67
 
40
68
  const allRepositories = 'All repositories';
41
69
 
@@ -54,74 +82,46 @@ const ContentViewRepositories = ({ cvId, details }) => {
54
82
  const error = useSelector(state => selectCVReposError(state, cvId), shallowEqual);
55
83
  const repoTypesResponse = useSelector(state => selectRepoTypes(state), shallowEqual);
56
84
  const repoTypesStatus = useSelector(state => selectRepoTypesStatus(state), shallowEqual);
57
- const { permissions } = details;
58
-
59
- const [rows, setRows] = useState([]);
60
- const deselectAll = () => setRows(rows.map(row => ({ ...row, selected: false })));
85
+ const { permissions, generated_for: generatedFor, import_only: importOnly } = details;
86
+ const generatedContentView = generatedFor !== 'none';
61
87
  const [searchQuery, updateSearchQuery] = useState('');
62
88
  const [typeSelected, setTypeSelected] = useState(allRepositories);
63
89
  const [statusSelected, setStatusSelected] = useState(ALL_STATUSES);
64
90
  // repoTypes object format: [displayed_value]: API_value
65
91
  const [repoTypes, setRepoTypes] = useState({});
66
92
  const [bulkActionOpen, setBulkActionOpen] = useState(false);
67
- const hasAddedSelected = rows.some(({ selected, added }) => selected && added);
68
- const hasNotAddedSelected = rows.some(({ selected, added }) => selected && !added);
93
+ const { repository_ids: repositoryIds = [] } = details;
94
+
95
+ const {
96
+ isSelected,
97
+ selectOne,
98
+ selectNone,
99
+ selectedCount,
100
+ selectedResults,
101
+ selectionSet,
102
+ isSelectable,
103
+ ...selectAll
104
+ } = useSelectionSet({
105
+ results,
106
+ metadata,
107
+ });
108
+
109
+ const hasAddedSelected = selectedResults.some(({ id }) => repositoryIds.includes(id));
110
+ const hasNotAddedSelected = selectedResults.some(({ id }) => !repositoryIds.includes(id));
69
111
 
70
112
  const columnHeaders = [
71
- { title: __('Type'), transforms: [fitContent] },
113
+ __('Type'),
72
114
  __('Name'),
73
115
  __('Product'),
74
116
  __('Sync state'),
75
117
  __('Content'),
76
- { title: __('Status') },
118
+ __('Status'),
77
119
  ];
78
- const loading = status === STATUS.PENDING;
79
-
80
- const buildRows = useCallback(() => {
81
- const newRows = [];
82
- results.forEach((repo) => {
83
- const {
84
- id,
85
- content_type: contentType,
86
- name,
87
- added_to_content_view: addedToCV,
88
- product: { id: productId, name: productName },
89
- content_counts: counts,
90
- last_sync_words: lastSyncWords,
91
- last_sync: lastSync,
92
- } = repo;
93
-
94
- const cells = [
95
- { title: <Bullseye><RepoIcon type={contentType} /></Bullseye> },
96
- { title: <a href={urlBuilder(`products/${productId}/repositories`, '', id)}>{name}</a> },
97
- productName,
98
- { title: <LastSync {...{ startedAt: lastSync?.started_at, lastSyncWords, lastSync }} /> },
99
- { title: <ContentCounts {...{ counts, productId }} repoId={id} /> },
100
- {
101
- title: <AddedStatusLabel added={addedToCV || statusSelected === ADDED} />,
102
- },
103
- ];
104
- newRows.push({
105
- repoId: id,
106
- cells,
107
- added: addedToCV || statusSelected === ADDED,
108
- });
109
- });
110
- return newRows;
111
- }, [statusSelected, results]);
112
-
113
- useDeepCompareEffect(() => {
114
- if (!loading && results) {
115
- const newRows = buildRows(results);
116
- setRows(newRows);
117
- }
118
- }, [response, loading, buildRows, results]);
119
120
 
120
121
  useEffect(() => {
121
122
  dispatch(getRepositoryTypes());
122
123
  }, []); // eslint-disable-line react-hooks/exhaustive-deps
123
124
 
124
-
125
125
  // Get repo type filter selections dynamically from the API
126
126
  useDeepCompareEffect(() => {
127
127
  if (repoTypesStatus === STATUS.RESOLVED && repoTypesResponse) {
@@ -137,12 +137,12 @@ const ContentViewRepositories = ({ cvId, details }) => {
137
137
  }
138
138
  }, [repoTypesResponse, repoTypesStatus]);
139
139
 
140
+
140
141
  const toggleBulkAction = () => {
141
142
  setBulkActionOpen(!bulkActionOpen);
142
143
  };
143
144
 
144
145
  const onAdd = (repos) => {
145
- const { repository_ids: repositoryIds = [] } = details;
146
146
  dispatch(updateContentView(
147
147
  cvId,
148
148
  { repository_ids: repositoryIds.concat(repos) },
@@ -159,7 +159,6 @@ const ContentViewRepositories = ({ cvId, details }) => {
159
159
 
160
160
  const onRemove = (repos) => {
161
161
  const reposToDelete = [].concat(repos);
162
- const { repository_ids: repositoryIds = [] } = details;
163
162
  const deletedRepos = repositoryIds.filter(x => !reposToDelete.includes(x));
164
163
  dispatch(updateContentView(
165
164
  cvId, { repository_ids: deletedRepos },
@@ -176,49 +175,42 @@ const ContentViewRepositories = ({ cvId, details }) => {
176
175
 
177
176
  const addBulk = () => {
178
177
  setBulkActionOpen(false);
179
- const reposToAdd = rows.filter(({ selected, added }) =>
180
- selected && !added).map(({ repoId }) => repoId);
181
- deselectAll();
178
+ const reposToAdd = selectedResults.filter(selectedRepo =>
179
+ !repositoryIds.includes(selectedRepo.id)).map(({ id }) => id);
180
+ selectNone();
182
181
  onAdd(reposToAdd);
183
182
  };
184
183
 
185
184
  const removeBulk = () => {
186
185
  setBulkActionOpen(false);
187
- const reposToDelete = rows.filter(({ selected, added }) =>
188
- selected && added).map(({ repoId }) => repoId);
189
- deselectAll();
186
+ const reposToDelete = selectedResults.filter(selectedRepo =>
187
+ repositoryIds.includes(selectedRepo.id)).map(({ id }) => id);
188
+ selectNone();
190
189
  onRemove(reposToDelete);
191
190
  };
192
191
 
193
- const actionResolver = ({
194
- parent,
195
- compoundParent,
196
- noactions,
197
- added,
198
- }) => {
199
- if (parent || compoundParent || noactions) return null;
200
- return [
201
- {
202
- title: 'Add',
203
- isDisabled: added,
204
- onClick: (_event, _rowId, rowInfo) => {
205
- onAdd(rowInfo.repoId);
206
- },
192
+ const rowDropdownItems = ({ id }) => [
193
+ {
194
+ title: 'Add',
195
+ ouiaId: `add-repository-${id}`,
196
+ isDisabled: importOnly || generatedContentView || repositoryIds.includes(id),
197
+ onClick: () => {
198
+ onAdd(id);
207
199
  },
208
- {
209
- title: 'Remove',
210
- isDisabled: !added,
211
- onClick: (_event, _rowId, rowInfo) => {
212
- onRemove(rowInfo.repoId);
213
- },
200
+ },
201
+ {
202
+ title: 'Remove',
203
+ ouiaId: `remove-repository-${id}`,
204
+ isDisabled: importOnly || generatedContentView || !repositoryIds.includes(id),
205
+ onClick: () => {
206
+ onRemove(id);
214
207
  },
215
- ];
216
- };
208
+ },
209
+ ];
217
210
 
218
211
  const getCVReposWithOptions = useCallback((params = {}) => {
219
212
  const allParams = { ...params };
220
213
  if (typeSelected !== 'All repositories') allParams.content_type = repoTypes[typeSelected];
221
-
222
214
  return getContentViewRepositories(cvId, allParams, statusSelected);
223
215
  }, [cvId, repoTypes, statusSelected, typeSelected]);
224
216
 
@@ -230,7 +222,7 @@ const ContentViewRepositories = ({ cvId, details }) => {
230
222
  const defaultFilters = [allRepositories, ALL_STATUSES];
231
223
 
232
224
  const dropdownItems = [
233
- <DropdownItem aria-label="bulk_remove" key="bulk_remove" isDisabled={!hasAddedSelected} component="button" onClick={removeBulk}>
225
+ <DropdownItem ouiaId="bulk-remove-repositories" aria-label="bulk_remove" key="bulk_remove" isDisabled={!hasAddedSelected} component="button" onClick={removeBulk}>
234
226
  {__('Remove')}
235
227
  </DropdownItem>,
236
228
  ];
@@ -238,7 +230,6 @@ const ContentViewRepositories = ({ cvId, details }) => {
238
230
  return (
239
231
  <TableWrapper
240
232
  {...{
241
- rows,
242
233
  metadata,
243
234
  emptyContentTitle,
244
235
  emptyContentBody,
@@ -250,14 +241,16 @@ const ContentViewRepositories = ({ cvId, details }) => {
250
241
  status,
251
242
  activeFilters,
252
243
  defaultFilters,
244
+ selectedCount,
245
+ selectNone,
253
246
  }}
254
- actionResolver={hasPermission(permissions, 'edit_content_views') ? actionResolver : null}
255
- onSelect={hasPermission(permissions, 'edit_content_views') ? onSelect(rows, setRows) : null}
256
- cells={columnHeaders}
247
+ ouiaId="content-view-repositories-table"
248
+ {...selectAll}
257
249
  variant={TableVariant.compact}
258
250
  autocompleteEndpoint="/repositories/auto_complete_search"
259
251
  fetchItems={useCallback(params => getCVReposWithOptions(params), [getCVReposWithOptions])}
260
252
  additionalListeners={[typeSelected, statusSelected]}
253
+ displaySelectAllCheckbox={hasPermission(permissions, 'edit_content_views')}
261
254
  actionButtons={
262
255
  <Split hasGutter>
263
256
  <SplitItem>
@@ -284,12 +277,13 @@ const ContentViewRepositories = ({ cvId, details }) => {
284
277
  <SplitItem>
285
278
  <ActionList>
286
279
  <ActionListItem>
287
- <Button onClick={addBulk} isDisabled={!hasNotAddedSelected} variant="primary" aria-label="add_repositories">
280
+ <Button ouiaId="add-repositories" onClick={addBulk} isDisabled={!hasNotAddedSelected || importOnly || generatedContentView} variant="primary" aria-label="add_repositories">
288
281
  {__('Add repositories')}
289
282
  </Button>
290
283
  </ActionListItem>
291
284
  <ActionListItem>
292
285
  <Dropdown
286
+ ouiaId="repositoies-bulk-actions"
293
287
  toggle={<KebabToggle aria-label="bulk_actions" onToggle={toggleBulkAction} />}
294
288
  isOpen={bulkActionOpen}
295
289
  isPlain
@@ -301,7 +295,64 @@ const ContentViewRepositories = ({ cvId, details }) => {
301
295
  }
302
296
  </Split>
303
297
  }
304
- />
298
+ >
299
+ <Thead>
300
+ <Tr key="version-header">
301
+ {hasPermission(permissions, 'edit_content_views') && <Th key="select-all" />}
302
+ {columnHeaders.map((title, index) => {
303
+ if (index === 0) {
304
+ return <Th modifier="fitContent" key={`col-header-${title}`}>{title}</Th>;
305
+ }
306
+ return <Th key={`col-header-${title}`}>{title}</Th>;
307
+ })}
308
+ </Tr>
309
+ </Thead>
310
+ <Tbody>
311
+ {results?.map((repo) => {
312
+ const {
313
+ id,
314
+ content_type: contentType,
315
+ name,
316
+ added_to_content_view: addedToCV,
317
+ product: { id: productId, name: productName },
318
+ content_counts: counts,
319
+ last_sync_words: lastSyncWords,
320
+ last_sync: lastSync,
321
+ } = repo;
322
+ return (
323
+ <Tr key={id} ouiaId={`repositories-table-row-${productName}-${name}`}>
324
+ {hasPermission(permissions, 'edit_content_views') &&
325
+ <Td>
326
+ <Checkbox
327
+ id={id}
328
+ isChecked={isSelected(id)}
329
+ onChange={selected =>
330
+ selectOne(selected, id, repo)
331
+ }
332
+ />
333
+ </Td>
334
+ }
335
+ <Td><Bullseye><RepoIcon type={contentType} /></Bullseye></Td>
336
+ <Td>
337
+ <a href={urlBuilder(`products/${productId}/repositories`, '', id)}>{name}</a>
338
+ </Td>
339
+ <Td>{productName}</Td>
340
+ <Td>
341
+ <LastSync {...{ startedAt: lastSync?.started_at, lastSyncWords, lastSync }} />
342
+ </Td>
343
+ <Td><ContentCounts {...{ counts, productId }} repoId={id} /></Td>
344
+ <Td><AddedStatusLabel added={addedToCV || statusSelected === ADDED} /></Td>
345
+ {hasPermission(permissions, 'edit_content_views') &&
346
+ <Td
347
+ actions={{
348
+ items: rowDropdownItems(repo),
349
+ }}
350
+ />}
351
+ </Tr>
352
+ );
353
+ })}
354
+ </Tbody>
355
+ </TableWrapper>
305
356
  );
306
357
  };
307
358
 
@@ -310,6 +361,8 @@ ContentViewRepositories.propTypes = {
310
361
  details: PropTypes.shape({
311
362
  repository_ids: PropTypes.arrayOf(PropTypes.number),
312
363
  permissions: PropTypes.shape({}),
364
+ import_only: PropTypes.bool,
365
+ generated_for: PropTypes.string,
313
366
  }).isRequired,
314
367
  };
315
368