katello 4.6.2.1 → 4.7.0.rc1

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 (333) hide show
  1. checksums.yaml +4 -4
  2. data/app/assets/javascripts/katello/common/vendor.js +0 -1
  3. data/app/controllers/katello/api/v2/activation_keys_controller.rb +1 -0
  4. data/app/controllers/katello/api/v2/alternate_content_sources_controller.rb +4 -4
  5. data/app/controllers/katello/api/v2/capsule_content_controller.rb +5 -0
  6. data/app/controllers/katello/api/v2/content_imports_controller.rb +1 -0
  7. data/app/controllers/katello/api/v2/content_view_components_controller.rb +1 -1
  8. data/app/controllers/katello/api/v2/host_subscriptions_controller.rb +2 -1
  9. data/app/controllers/katello/api/v2/hosts_bulk_actions_controller.rb +1 -1
  10. data/app/controllers/katello/api/v2/organizations_controller.rb +1 -0
  11. data/app/controllers/katello/api/v2/repositories_controller.rb +78 -12
  12. data/app/controllers/katello/api/v2/upstream_subscriptions_controller.rb +1 -1
  13. data/app/controllers/katello/concerns/api/v2/registration_controller_extensions.rb +7 -1
  14. data/app/controllers/katello/concerns/api/v2/smart_proxies_controller_extensions.rb +1 -0
  15. data/app/controllers/katello/concerns/hosts_controller_extensions.rb +11 -9
  16. data/app/helpers/katello/content_source_helper.rb +9 -0
  17. data/app/helpers/katello/hosts_and_hostgroups_helper.rb +31 -0
  18. data/app/lib/actions/katello/activation_key/destroy.rb +1 -0
  19. data/app/lib/actions/katello/agent_action.rb +1 -0
  20. data/app/lib/actions/katello/alternate_content_source/create.rb +1 -1
  21. data/app/lib/actions/katello/alternate_content_source/update.rb +2 -2
  22. data/app/lib/actions/katello/capsule_content/sync.rb +10 -2
  23. data/app/lib/actions/katello/cdn_configuration/update.rb +1 -1
  24. data/app/lib/actions/katello/content_view/promote.rb +1 -0
  25. data/app/lib/actions/katello/content_view/publish.rb +5 -2
  26. data/app/lib/actions/katello/content_view_version/auto_create_redhat_repositories.rb +7 -3
  27. data/app/lib/actions/katello/content_view_version/auto_create_repositories.rb +4 -2
  28. data/app/lib/actions/katello/content_view_version/import.rb +22 -10
  29. data/app/lib/actions/katello/product/destroy.rb +1 -1
  30. data/app/lib/actions/katello/repository/destroy.rb +3 -3
  31. data/app/lib/actions/katello/repository/errata_mail.rb +9 -6
  32. data/app/lib/actions/katello/repository/refresh_repository.rb +1 -1
  33. data/app/lib/actions/katello/repository/sync.rb +13 -6
  34. data/app/lib/actions/katello/repository_set/enable_repository.rb +6 -2
  35. data/app/lib/actions/pulp3/alternate_content_source/refresh_remote.rb +16 -0
  36. data/app/lib/actions/pulp3/orchestration/alternate_content_source/refresh.rb +1 -0
  37. data/app/lib/actions/pulp3/orchestration/content_view_version/export_library.rb +1 -1
  38. data/app/lib/actions/pulp3/orchestration/content_view_version/export_repository.rb +10 -2
  39. data/app/lib/katello/concerns/renderer_extensions.rb +2 -1
  40. data/app/lib/katello/errors.rb +2 -2
  41. data/app/lib/katello/resources/candlepin.rb +7 -1
  42. data/app/lib/katello/resources/cdn/katello_cdn.rb +3 -13
  43. data/app/lib/katello/resources/cdn.rb +14 -9
  44. data/app/lib/katello/util/candlepin_repository_checker.rb +73 -0
  45. data/app/models/katello/activation_key.rb +12 -1
  46. data/app/models/katello/alternate_content_source.rb +15 -4
  47. data/app/models/katello/alternate_content_source_product.rb +1 -1
  48. data/app/models/katello/authorization/repository.rb +2 -2
  49. data/app/models/katello/cdn_configuration.rb +12 -3
  50. data/app/models/katello/concerns/host_managed_extensions.rb +15 -2
  51. data/app/models/katello/concerns/http_proxy_extensions.rb +5 -10
  52. data/app/models/katello/concerns/smart_proxy_extensions.rb +30 -15
  53. data/app/models/katello/content.rb +15 -0
  54. data/app/models/katello/content_credential.rb +8 -9
  55. data/app/models/katello/content_view.rb +7 -3
  56. data/app/models/katello/content_view_component.rb +4 -0
  57. data/app/models/katello/content_view_version.rb +1 -1
  58. data/app/models/katello/erratum.rb +6 -2
  59. data/app/models/katello/host/content_facet.rb +13 -3
  60. data/app/models/katello/repository.rb +15 -1
  61. data/app/models/katello/root_repository.rb +0 -2
  62. data/app/overrides/add_smart_proxy_form.rb +5 -0
  63. data/app/presenters/katello/content_view_version_compare_presenter.rb +5 -0
  64. data/app/presenters/katello/host_package_presenter.rb +4 -4
  65. data/app/services/katello/pulp3/alternate_content_source.rb +23 -15
  66. data/app/services/katello/pulp3/ansible_collection.rb +7 -10
  67. data/app/services/katello/pulp3/content_view_version/export.rb +19 -6
  68. data/app/services/katello/pulp3/content_view_version/import.rb +2 -0
  69. data/app/services/katello/pulp3/content_view_version/import_validator.rb +21 -5
  70. data/app/services/katello/pulp3/content_view_version/importable_products.rb +11 -1
  71. data/app/services/katello/pulp3/content_view_version/importable_repositories.rb +38 -9
  72. data/app/services/katello/pulp3/content_view_version/metadata_generator.rb +12 -5
  73. data/app/services/katello/pulp3/content_view_version/metadata_map.rb +13 -2
  74. data/app/services/katello/pulp3/content_view_version/syncable_format_export.rb +5 -1
  75. data/app/services/katello/pulp3/pulp_content_unit.rb +3 -0
  76. data/app/services/katello/pulp3/repository.rb +18 -6
  77. data/app/services/katello/pulp3/repository_mirror.rb +0 -1
  78. data/app/services/katello/pulp3/smart_proxy_mirror_repository.rb +2 -2
  79. data/app/services/katello/pulp3/task_group.rb +18 -1
  80. data/app/services/katello/repository_type.rb +5 -2
  81. data/app/services/katello/repository_type_manager.rb +4 -3
  82. data/app/views/dashboard/_content_views_widget.html.erb +1 -1
  83. data/app/views/foreman/job_templates/change_content_source.erb +6 -0
  84. data/app/views/foreman/job_templates/update_packages_by_search_query.erb +7 -1
  85. data/app/views/katello/api/v2/alternate_content_sources/base.json.rabl +4 -4
  86. data/app/views/katello/api/v2/alternate_content_sources/index.json.rabl +1 -0
  87. data/app/views/katello/api/v2/alternate_content_sources/permissions.rabl +11 -0
  88. data/app/views/katello/api/v2/content_credentials/show.json.rabl +12 -0
  89. data/app/views/katello/api/v2/content_views/permissions.rabl +1 -0
  90. data/app/views/katello/api/v2/host_packages/base.json.rabl +1 -1
  91. data/app/views/katello/api/v2/module_streams/show.json.rabl +7 -0
  92. data/app/views/katello/api/v2/repositories/compare.json.rabl +10 -0
  93. data/app/views/katello/api/v2/smart_proxies/pulp_info.json.rabl +1 -0
  94. data/app/views/katello/hosts/_errata_counts.html.erb +46 -0
  95. data/app/views/overrides/activation_keys/_host_synced_content_select.html.erb +1 -0
  96. data/app/views/overrides/smart_proxies/_acs_http_proxy.html.erb +6 -0
  97. data/config/initializers/monkeys.rb +1 -0
  98. data/config/routes/api/v2.rb +2 -0
  99. data/config/routes.rb +3 -0
  100. data/db/migrate/20220730033504_update_custom_cdn.rb +13 -0
  101. data/db/migrate/20220920173656_add_http_proxy_to_smart_proxy.rb +7 -0
  102. data/db/migrate/20220920180858_remove_http_proxy_from_katello_alternate_content_sources.rb +6 -0
  103. data/engines/bastion/app/assets/javascripts/bastion/components/notification.service.js +1 -1
  104. data/engines/bastion/app/views/bastion/layouts/assets.html.erb +5 -5
  105. data/engines/bastion/vendor/assets/javascripts/bastion/angular/angular.js +1 -1
  106. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/content-credentials/content-credential.factory.js +17 -0
  107. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/content-credentials/content-credentials.routes.js +10 -0
  108. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/content-credentials/details/content-credential-acs.controller.js +36 -0
  109. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/content-credentials/details/content-credential-details.controller.js +7 -1
  110. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/content-credentials/details/views/content-credential-acs.html +38 -0
  111. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/content-credentials/details/views/content-credential-details.html +3 -0
  112. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/content-credentials/views/content-credentials.html +7 -2
  113. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/content-hosts/content-hosts.controller.js +4 -2
  114. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/content-hosts/details/views/content-host-info.html +1 -1
  115. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/content-hosts/views/content-hosts.html +4 -3
  116. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/i18n/bastion_katello.pot +14 -1392
  117. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/katello-features.run.js +1 -0
  118. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/products/details/repositories/details/repository-details.controller.js +7 -0
  119. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/products/details/repositories/details/views/repository-details.html +1 -1
  120. data/lib/katello/permission_creator.rb +1 -0
  121. data/lib/katello/plugin.rb +34 -11
  122. data/lib/katello/repository_types/deb.rb +1 -1
  123. data/lib/katello/repository_types/docker.rb +1 -1
  124. data/lib/katello/repository_types/python.rb +3 -3
  125. data/lib/katello/tasks/check_candlepin_content.rake +16 -0
  126. data/lib/katello/tasks/reset.rake +1 -1
  127. data/lib/katello/version.rb +1 -1
  128. data/lib/monkeys/try_pulp_container_path.rb +35 -0
  129. data/locale/action_names.rb +7 -7
  130. data/locale/bn/katello.po +395 -63
  131. data/locale/cs/katello.po +396 -64
  132. data/locale/de/katello.po +399 -67
  133. data/locale/en/katello.po +395 -63
  134. data/locale/es/katello.po +399 -67
  135. data/locale/fr/katello.po +400 -68
  136. data/locale/gu/katello.po +395 -63
  137. data/locale/hi/katello.po +395 -63
  138. data/locale/it/katello.po +396 -64
  139. data/locale/ja/katello.po +400 -68
  140. data/locale/katello.pot +1916 -1213
  141. data/locale/kn/katello.po +395 -63
  142. data/locale/ko/katello.po +396 -64
  143. data/locale/mr/katello.po +395 -63
  144. data/locale/or/katello.po +395 -63
  145. data/locale/pa/katello.po +395 -63
  146. data/locale/pt/katello.po +395 -63
  147. data/locale/pt_BR/katello.po +399 -67
  148. data/locale/ru/katello.po +396 -64
  149. data/locale/ta/katello.po +395 -63
  150. data/locale/te/katello.po +395 -63
  151. data/locale/zh_CN/katello.po +400 -68
  152. data/locale/zh_TW/katello.po +396 -64
  153. data/webpack/components/Bookmark/index.js +5 -1
  154. data/webpack/components/Content/Details/ContentDetails.js +1 -1
  155. data/webpack/components/Content/Details/__tests__/__snapshots__/ContentDetails.test.js.snap +6 -0
  156. data/webpack/components/EditableSwitch.js +1 -0
  157. data/webpack/components/EditableTextInput/EditableTextInput.js +3 -3
  158. data/webpack/components/Errata/errataHelpers.js +33 -0
  159. data/webpack/components/Errata/index.js +45 -12
  160. data/webpack/components/Loading.js +18 -8
  161. data/webpack/components/Packages/index.js +8 -24
  162. data/webpack/components/RoutedTabs/index.js +1 -0
  163. data/webpack/components/Search/Search.js +20 -2
  164. data/webpack/components/Search/__tests__/search.test.js +3 -3
  165. data/webpack/components/Table/EmptyStateMessage.js +1 -1
  166. data/webpack/components/Table/PageControls.js +1 -0
  167. data/webpack/components/Table/TableHooks.js +4 -0
  168. data/webpack/components/Table/TableWrapper.js +7 -7
  169. data/webpack/components/TypeAhead/pf4Search/TypeAheadInput.js +1 -0
  170. data/webpack/components/TypeAhead/pf4Search/TypeAheadItems.js +2 -0
  171. data/webpack/components/TypeAhead/pf4Search/TypeAheadSearch.js +1 -1
  172. data/webpack/components/extensions/HostDetails/Cards/ContentViewDetailsCard/ChangeHostCVModal.js +3 -1
  173. data/webpack/components/extensions/HostDetails/Cards/ContentViewDetailsCard/ContentViewDetailsCard.js +2 -1
  174. data/webpack/components/extensions/HostDetails/Cards/ErrataOverviewCard.js +124 -68
  175. data/webpack/components/extensions/HostDetails/Cards/ErrataOverviewCard.scss +5 -0
  176. data/webpack/components/extensions/HostDetails/Cards/HostCollectionsCard/HostCollectionsCard.js +30 -4
  177. data/webpack/components/extensions/HostDetails/Cards/HostCollectionsCard/HostCollectionsCard.scss +23 -0
  178. data/webpack/components/extensions/HostDetails/Cards/HostCollectionsCard/HostCollectionsModal.js +5 -4
  179. data/webpack/components/extensions/HostDetails/Cards/HostCollectionsCard/__tests__/hostCollectionsCard.test.js +25 -10
  180. data/webpack/components/extensions/HostDetails/Cards/SystemPurposeCard/SystemPurposeCard.js +3 -3
  181. data/webpack/components/extensions/HostDetails/Cards/SystemPurposeCard/SystemPurposeEditModal.js +6 -0
  182. data/webpack/components/extensions/HostDetails/Cards/__tests__/errataOverviewCard.test.js +145 -32
  183. data/webpack/components/extensions/HostDetails/DetailsTabCards/RegistrationCard.js +3 -1
  184. data/webpack/components/extensions/HostDetails/Tabs/ContentTab/constants.js +2 -1
  185. data/webpack/components/extensions/HostDetails/Tabs/ContentTab/index.js +1 -0
  186. data/webpack/components/extensions/HostDetails/Tabs/ErrataTab/ErrataTab.js +78 -26
  187. data/webpack/components/extensions/HostDetails/Tabs/ModuleStreamsTab/ModuleStreamsTab.js +23 -10
  188. data/webpack/components/extensions/HostDetails/Tabs/PackagesTab/HostPackagesConstants.js +1 -0
  189. data/webpack/components/extensions/HostDetails/Tabs/PackagesTab/PackageInstallModal.js +9 -4
  190. data/webpack/components/extensions/HostDetails/Tabs/PackagesTab/PackagesTab.js +141 -23
  191. data/webpack/components/extensions/HostDetails/Tabs/PackagesTab/PackagesTab.scss +6 -1
  192. data/webpack/components/extensions/HostDetails/Tabs/RemoteExecutionActions.js +9 -8
  193. data/webpack/components/extensions/HostDetails/Tabs/RepositorySetsTab/RepositorySetsTab.js +24 -3
  194. data/webpack/components/extensions/HostDetails/Tabs/TracesTab/EnableTracerModal.js +7 -2
  195. data/webpack/components/extensions/HostDetails/Tabs/TracesTab/TracesEnabler.js +2 -1
  196. data/webpack/components/extensions/HostDetails/Tabs/TracesTab/TracesTab.js +20 -4
  197. data/webpack/components/extensions/HostDetails/Tabs/__tests__/errataTab.test.js +56 -38
  198. data/webpack/components/extensions/HostDetails/Tabs/__tests__/packages.fixtures.json +3 -3
  199. data/webpack/components/extensions/HostDetails/Tabs/__tests__/packagesTab.test.js +5 -4
  200. data/webpack/components/extensions/HostDetails/Tabs/customizedRexUrlHelpers.js +3 -3
  201. data/webpack/containers/Application/config.js +2 -2
  202. data/webpack/containers/Application/overrides.scss +12 -0
  203. data/webpack/global_test_setup.js +19 -1
  204. data/webpack/ouia_id_check.js +0 -2
  205. data/webpack/redux/actions/RedHatRepositories/helpers.js +4 -8
  206. data/webpack/scenes/AlternateContentSources/ACSActions.js +37 -6
  207. data/webpack/scenes/AlternateContentSources/ACSConstants.js +2 -0
  208. data/webpack/scenes/AlternateContentSources/ACSIndexPage.js +1 -1
  209. data/webpack/scenes/AlternateContentSources/ACSSelectors.js +6 -6
  210. data/webpack/scenes/AlternateContentSources/Acs.scss +3 -0
  211. data/webpack/scenes/AlternateContentSources/Create/ACSCreateWizard.js +24 -3
  212. data/webpack/scenes/AlternateContentSources/Create/Steps/ACSCreateFinish.js +10 -8
  213. data/webpack/scenes/AlternateContentSources/Create/Steps/ACSCredentials.js +25 -4
  214. data/webpack/scenes/AlternateContentSources/Create/Steps/ACSReview.js +22 -11
  215. data/webpack/scenes/AlternateContentSources/Create/Steps/ACSSmartProxies.js +27 -2
  216. data/webpack/scenes/AlternateContentSources/Create/Steps/AcsUrlPaths.js +49 -17
  217. data/webpack/scenes/AlternateContentSources/Create/Steps/SelectSource.js +76 -23
  218. data/webpack/scenes/AlternateContentSources/Create/__tests__/acsCreate.test.js +159 -11
  219. data/webpack/scenes/AlternateContentSources/Details/ACSExpandableDetails.js +83 -29
  220. data/webpack/scenes/AlternateContentSources/Details/EditModals/ACSEditCredentials.js +9 -8
  221. data/webpack/scenes/AlternateContentSources/Details/EditModals/ACSEditDetails.js +2 -2
  222. data/webpack/scenes/AlternateContentSources/Details/EditModals/ACSEditProducts.js +2 -2
  223. data/webpack/scenes/AlternateContentSources/Details/EditModals/ACSEditSmartProxies.js +39 -7
  224. data/webpack/scenes/AlternateContentSources/Details/EditModals/ACSEditURLPaths.js +27 -11
  225. data/webpack/scenes/AlternateContentSources/Details/__tests__/ACSEdits.test.js +58 -55
  226. data/webpack/scenes/AlternateContentSources/Details/__tests__/ACSExpandableDetails.test.js +35 -32
  227. data/webpack/scenes/AlternateContentSources/MainTable/ACSTable.js +323 -150
  228. data/webpack/scenes/AlternateContentSources/MainTable/__tests__/acsIndex.fixtures.json +5 -1
  229. data/webpack/scenes/AlternateContentSources/MainTable/__tests__/acsTable.test.js +10 -11
  230. data/webpack/scenes/AlternateContentSources/helpers.js +26 -0
  231. data/webpack/scenes/ContentViews/ContentViewsConstants.js +1 -0
  232. data/webpack/scenes/ContentViews/ContentViewsPage.js +1 -1
  233. data/webpack/scenes/ContentViews/Copy/CopyContentViewForm.js +1 -0
  234. data/webpack/scenes/ContentViews/Copy/CopyContentViewModal.js +1 -0
  235. data/webpack/scenes/ContentViews/Create/ContentViewFormComponents.js +10 -5
  236. data/webpack/scenes/ContentViews/Create/CreateContentViewForm.js +30 -7
  237. data/webpack/scenes/ContentViews/Create/CreateContentViewModal.js +1 -0
  238. data/webpack/scenes/ContentViews/Create/__tests__/createContentView.test.js +21 -6
  239. data/webpack/scenes/ContentViews/Delete/Steps/CVDeleteEnvironmentsSelection.js +3 -3
  240. data/webpack/scenes/ContentViews/Delete/Steps/CVDeletionReassignActivationKeysForm.js +1 -0
  241. data/webpack/scenes/ContentViews/Delete/Steps/CVDeletionReassignHostsForm.js +1 -0
  242. data/webpack/scenes/ContentViews/Delete/__tests__/CvData.fixtures.json +2 -0
  243. data/webpack/scenes/ContentViews/Details/ComponentContentViews/ComponentContentViewAddModal.js +3 -0
  244. data/webpack/scenes/ContentViews/Details/ComponentContentViews/ComponentContentViewBulkAddModal.js +4 -1
  245. data/webpack/scenes/ContentViews/Details/ComponentContentViews/ComponentVersion.js +1 -1
  246. data/webpack/scenes/ContentViews/Details/ComponentContentViews/ContentViewComponents.js +2 -1
  247. data/webpack/scenes/ContentViews/Details/ContentViewDetailActions.js +14 -0
  248. data/webpack/scenes/ContentViews/Details/ContentViewDetailSelectors.js +11 -1
  249. data/webpack/scenes/ContentViews/Details/ContentViewDetails.js +1 -1
  250. data/webpack/scenes/ContentViews/Details/ContentViewInfo.js +2 -0
  251. data/webpack/scenes/ContentViews/Details/Filters/Add/CVFilterAddModal.js +5 -0
  252. data/webpack/scenes/ContentViews/Details/Filters/AffectedRepositories/AffectedRepositorySelection.js +1 -0
  253. data/webpack/scenes/ContentViews/Details/Filters/ArtifactsWithNoErrata.js +1 -0
  254. data/webpack/scenes/ContentViews/Details/Filters/CVContainerImageFilterContent.js +8 -2
  255. data/webpack/scenes/ContentViews/Details/Filters/CVDebFilterContent.js +5 -1
  256. data/webpack/scenes/ContentViews/Details/Filters/CVErrataDateFilterContent.js +22 -6
  257. data/webpack/scenes/ContentViews/Details/Filters/CVErrataIDFilterContent.js +19 -9
  258. data/webpack/scenes/ContentViews/Details/Filters/CVModuleStreamFilterContent.js +9 -2
  259. data/webpack/scenes/ContentViews/Details/Filters/CVPackageGroupFilterContent.js +9 -2
  260. data/webpack/scenes/ContentViews/Details/Filters/CVRpmFilterContent.js +8 -2
  261. data/webpack/scenes/ContentViews/Details/Filters/ContentViewFilterDetailsHeader.js +1 -1
  262. data/webpack/scenes/ContentViews/Details/Filters/ContentViewFilters.js +2 -1
  263. data/webpack/scenes/ContentViews/Details/Filters/MatchContentModal/CVRpmMatchContentModal.js +3 -2
  264. data/webpack/scenes/ContentViews/Details/Filters/MatchContentModal/__tests__/CVRpmMatchContentModal.test.js +1 -1
  265. data/webpack/scenes/ContentViews/Details/Filters/__tests__/CVContainerImageFilterContent.test.js +2 -2
  266. data/webpack/scenes/ContentViews/Details/Filters/__tests__/CVRpmFilterContent.test.js +1 -1
  267. data/webpack/scenes/ContentViews/Details/Filters/__tests__/contentViewFilterDetails.test.js +1 -1
  268. data/webpack/scenes/ContentViews/Details/Filters/__tests__/contentViewFilters.test.js +1 -1
  269. data/webpack/scenes/ContentViews/Details/Histories/ContentViewHistories.js +2 -2
  270. data/webpack/scenes/ContentViews/Details/Promote/ContentViewVersionPromote.js +2 -0
  271. data/webpack/scenes/ContentViews/Details/Repositories/ContentViewRepositories.js +2 -1
  272. data/webpack/scenes/ContentViews/Details/Versions/BulkDelete/Steps/ReviewEnvironments.js +3 -3
  273. data/webpack/scenes/ContentViews/Details/Versions/Compare/CVVersionCompare.js +9 -1
  274. data/webpack/scenes/ContentViews/Details/Versions/Compare/CVVersionCompareConfig.js +83 -0
  275. data/webpack/scenes/ContentViews/Details/Versions/Compare/CVVersionCompareTable.js +32 -8
  276. data/webpack/scenes/ContentViews/Details/Versions/Compare/__tests__/CVVersionCompare.test.js +56 -3
  277. data/webpack/scenes/ContentViews/Details/Versions/Compare/__tests__/cvCompareRepositories.fixtures.json +175 -0
  278. data/webpack/scenes/ContentViews/Details/Versions/ContentViewVersions.js +6 -2
  279. data/webpack/scenes/ContentViews/Details/Versions/Delete/RemoveSteps/CVEnvironmentSelectionForm.js +3 -3
  280. data/webpack/scenes/ContentViews/Details/Versions/Delete/RemoveSteps/CVReassignActivationKeysForm.js +1 -0
  281. data/webpack/scenes/ContentViews/Details/Versions/Delete/RemoveSteps/CVReassignHostsForm.js +1 -0
  282. data/webpack/scenes/ContentViews/Details/Versions/Delete/affectedActivationKeys.js +2 -2
  283. data/webpack/scenes/ContentViews/Details/Versions/Delete/affectedHosts.js +2 -2
  284. data/webpack/scenes/ContentViews/Details/Versions/VersionDetails/ContentViewVersionDetailConfig.js +2 -2
  285. data/webpack/scenes/ContentViews/Details/Versions/VersionDetails/ContentViewVersionDetails.js +1 -0
  286. data/webpack/scenes/ContentViews/Details/Versions/VersionDetails/ContentViewVersionDetailsHeader.js +4 -1
  287. data/webpack/scenes/ContentViews/Details/Versions/VersionDetails/ContentViewVersionDetailsTable.js +5 -4
  288. data/webpack/scenes/ContentViews/Publish/CVPublishForm.js +5 -1
  289. data/webpack/scenes/ContentViews/Publish/CVPublishReview.js +3 -3
  290. data/webpack/scenes/ContentViews/Table/ContentViewsTable.js +10 -5
  291. data/webpack/scenes/ContentViews/__tests__/basicContentViews.fixtures.js +2 -0
  292. data/webpack/scenes/ContentViews/__tests__/contentViewList.fixtures.json +1 -0
  293. data/webpack/scenes/ContentViews/__tests__/contentViewPage.test.js +81 -19
  294. data/webpack/scenes/ContentViews/components/CVBreadCrumb.js +1 -1
  295. data/webpack/scenes/ContentViews/components/EnvironmentPaths/EnvironmentPaths.js +1 -0
  296. data/webpack/scenes/ContentViews/components/InactiveText.js +9 -1
  297. data/webpack/scenes/ContentViews/expansions/RelatedCompositeContentViewsModal.js +4 -2
  298. data/webpack/scenes/ContentViews/expansions/RelatedContentViewComponentsModal.js +3 -2
  299. data/webpack/scenes/Hosts/ChangeContentSource/actions.js +18 -11
  300. data/webpack/scenes/Hosts/ChangeContentSource/components/ContentSourceForm.js +15 -8
  301. data/webpack/scenes/Hosts/ChangeContentSource/components/FormField.js +3 -4
  302. data/webpack/scenes/Hosts/ChangeContentSource/components/Hosts.js +55 -0
  303. data/webpack/scenes/Hosts/ChangeContentSource/components/HostsModal.js +59 -0
  304. data/webpack/scenes/Hosts/ChangeContentSource/constants.js +1 -0
  305. data/webpack/scenes/Hosts/ChangeContentSource/helpers.js +2 -5
  306. data/webpack/scenes/Hosts/ChangeContentSource/index.js +46 -41
  307. data/webpack/scenes/Hosts/ChangeContentSource/selectors.js +5 -5
  308. data/webpack/scenes/ModuleStreams/Details/ModuleDetailsSchema.js +10 -1
  309. data/webpack/scenes/ModuleStreams/Details/ModuleStreamDetails.js +1 -1
  310. data/webpack/scenes/ModuleStreams/Details/__tests__/__snapshots__/ModuleStreamDetails.test.js.snap +97 -2
  311. data/webpack/scenes/Organizations/OrganizationSelectors.js +1 -0
  312. data/webpack/scenes/Subscriptions/Manifest/CdnConfigurationTab/CdnConfigurationConstants.js +2 -1
  313. data/webpack/scenes/Subscriptions/Manifest/CdnConfigurationTab/CdnTypeForm.js +10 -25
  314. data/webpack/scenes/Subscriptions/Manifest/CdnConfigurationTab/CustomCdnTypeForm.js +154 -0
  315. data/webpack/scenes/Subscriptions/Manifest/CdnConfigurationTab/ExportSyncForm.js +4 -4
  316. data/webpack/scenes/Subscriptions/Manifest/CdnConfigurationTab/NetworkSyncForm.js +59 -44
  317. data/webpack/scenes/Subscriptions/Manifest/CdnConfigurationTab/__tests__/CdnTypeForm.test.js +3 -28
  318. data/webpack/scenes/Subscriptions/Manifest/CdnConfigurationTab/__tests__/CustomCdnTypeForm.test.js +97 -0
  319. data/webpack/scenes/Subscriptions/Manifest/CdnConfigurationTab/__tests__/ExportSyncForm.test.js +1 -1
  320. data/webpack/scenes/Subscriptions/Manifest/CdnConfigurationTab/__tests__/NetworkSyncForm.test.js +4 -4
  321. data/webpack/scenes/Subscriptions/Manifest/CdnConfigurationTab/index.js +23 -10
  322. data/webpack/scenes/Subscriptions/Manifest/ManageManifestModal.js +1 -1
  323. data/webpack/scenes/Subscriptions/SubscriptionConstants.js +2 -1
  324. data/webpack/scenes/Subscriptions/SubscriptionsPage.js +5 -5
  325. data/webpack/scenes/Subscriptions/UpstreamSubscriptions/UpstreamSubscriptionsPage.js +3 -3
  326. data/webpack/scenes/Subscriptions/UpstreamSubscriptions/__tests__/__snapshots__/UpstreamSubscriptionsPage.test.js.snap +2 -2
  327. data/webpack/scenes/Subscriptions/__tests__/__snapshots__/SubscriptionsPage.test.js.snap +3 -3
  328. data/webpack/scenes/Subscriptions/components/SubscriptionsToolbar/SubscriptionsToolbar.js +3 -3
  329. data/webpack/scenes/Tasks/helpers.js +14 -7
  330. metadata +54 -35
  331. data/app/lib/actions/pulp3/orchestration/alternate_content_source/refresh_remote.rb +0 -18
  332. data/db/migrate/20221206170122_update_ignore_srpm_to_false_for_mirror_complete.rb +0 -5
  333. data/vendor/assets/javascripts/katello/jquery.trunk8.js +0 -203
@@ -41,7 +41,11 @@ const ContentViewTable = () => {
41
41
  const [actionableCvName, setActionableCvName] = useState('');
42
42
  const dispatch = useDispatch();
43
43
  const metadata = omit(response, ['results']);
44
- const { can_create: canCreate = false, results } = response;
44
+ const {
45
+ can_create: canCreate = false,
46
+ can_view: canView = false,
47
+ results,
48
+ } = response;
45
49
  const columnHeaders = [
46
50
  __('Type'),
47
51
  __('Name'),
@@ -152,6 +156,7 @@ const ContentViewTable = () => {
152
156
  fetchItems,
153
157
  showPrimaryAction,
154
158
  }}
159
+ hideSearch={!canView}
155
160
  ouiaId="content-views-table"
156
161
  additionalListeners={[activeSortColumn, activeSortDirection]}
157
162
  bookmarkController="katello_content_views"
@@ -168,7 +173,7 @@ const ContentViewTable = () => {
168
173
  </Button >) : undefined}
169
174
  actionButtons={
170
175
  <>
171
- {results?.length !== 0 &&
176
+ {results?.length !== 0 && canCreate &&
172
177
  <Button ouiaId="create-content-view" onClick={openForm} variant="primary" aria-label="create_content_view">
173
178
  {__('Create content view')}
174
179
  </Button>
@@ -214,7 +219,7 @@ const ContentViewTable = () => {
214
219
  }
215
220
  >
216
221
  <Thead>
217
- <Tr>
222
+ <Tr ouiaId="cvTableHeaderRow">
218
223
  <Th key="expand-carat" />
219
224
  {columnHeaders.map(col => (
220
225
  <Th
@@ -249,7 +254,7 @@ const ContentViewTable = () => {
249
254
  const isExpanded = tableRowIsExpanded(cvId);
250
255
  return (
251
256
  <Tbody isExpanded={isExpanded} key={`${cvId}_${createdAt}`}>
252
- <Tr key={cvId}>
257
+ <Tr key={cvId} ouiaId={`ContentViewTableRow-${cvId}`}>
253
258
  <Td
254
259
  expand={{
255
260
  rowIndex,
@@ -279,7 +284,7 @@ const ContentViewTable = () => {
279
284
  }}
280
285
  />
281
286
  </Tr>
282
- <Tr key="child_row" isExpanded={isExpanded}>
287
+ <Tr key="child_row" ouiaId={`ContentViewTableRowChild-${cvId}`} isExpanded={isExpanded}>
283
288
  <Td colSpan={2}>
284
289
  <ExpandableRowContent>
285
290
  <DetailsExpansion
@@ -15,6 +15,8 @@ const createBasicCVs = (amount) => {
15
15
  total: amount,
16
16
  subtotal: amount,
17
17
  page: 1,
18
+ can_create: true,
19
+ can_view: true,
18
20
  per_page: 20,
19
21
  error: null,
20
22
  search: null,
@@ -10,6 +10,7 @@
10
10
  "order": "asc"
11
11
  },
12
12
  "can_create": true,
13
+ "can_view": true,
13
14
  "results": [
14
15
  {
15
16
  "composite": false,
@@ -22,17 +22,6 @@ let scopeBookmark;
22
22
  beforeEach(() => {
23
23
  const { results } = cvIndexData;
24
24
  [firstCV] = results;
25
- scopeBookmark = nockInstance
26
- .get('/api/v2/bookmarks')
27
- .query(true)
28
- .reply(200, {});
29
- searchDelayScope = mockSetting(nockInstance, 'autosearch_delay', 0);
30
- autoSearchScope = mockSetting(nockInstance, 'autosearch_while_typing');
31
- });
32
-
33
- afterEach(() => {
34
- assertNockRequest(searchDelayScope);
35
- assertNockRequest(autoSearchScope);
36
25
  });
37
26
 
38
27
  test('Can call API for CVs and show on screen on page load', async (done) => {
@@ -41,6 +30,12 @@ test('Can call API for CVs and show on screen on page load', async (done) => {
41
30
  .get(cvIndexPath)
42
31
  .query(true)
43
32
  .reply(200, cvIndexData);
33
+ searchDelayScope = mockSetting(nockInstance, 'autosearch_delay', 0);
34
+ autoSearchScope = mockSetting(nockInstance, 'autosearch_while_typing');
35
+ scopeBookmark = nockInstance
36
+ .get('/api/v2/bookmarks')
37
+ .query(true)
38
+ .reply(200, {});
44
39
 
45
40
  const { queryByText, queryAllByText } = renderWithRedux(<ContentViewsPage />, renderOptions);
46
41
 
@@ -56,6 +51,8 @@ test('Can call API for CVs and show on screen on page load', async (done) => {
56
51
 
57
52
  assertNockRequest(scopeBookmark);
58
53
  assertNockRequest(autocompleteScope);
54
+ assertNockRequest(searchDelayScope);
55
+ assertNockRequest(autoSearchScope);
59
56
  assertNockRequest(scope, done);
60
57
  });
61
58
 
@@ -65,6 +62,12 @@ test('Can show last task and link to it', async (done) => {
65
62
  .get(cvIndexPath)
66
63
  .query(true)
67
64
  .reply(200, cvIndexData);
65
+ searchDelayScope = mockSetting(nockInstance, 'autosearch_delay', 0);
66
+ autoSearchScope = mockSetting(nockInstance, 'autosearch_while_typing');
67
+ scopeBookmark = nockInstance
68
+ .get('/api/v2/bookmarks')
69
+ .query(true)
70
+ .reply(200, {});
68
71
 
69
72
  const { getByText, queryByText } = renderWithRedux(<ContentViewsPage />, renderOptions);
70
73
 
@@ -81,6 +84,8 @@ test('Can show last task and link to it', async (done) => {
81
84
 
82
85
  assertNockRequest(scopeBookmark);
83
86
  assertNockRequest(autocompleteScope);
87
+ assertNockRequest(searchDelayScope);
88
+ assertNockRequest(autoSearchScope);
84
89
  assertNockRequest(scope, done); // Pass jest callback to confirm test is done
85
90
  });
86
91
 
@@ -90,6 +95,12 @@ test('Can show latest version and link to it', async (done) => {
90
95
  .get(cvIndexPath)
91
96
  .query(true)
92
97
  .reply(200, cvIndexData);
98
+ searchDelayScope = mockSetting(nockInstance, 'autosearch_delay', 0);
99
+ autoSearchScope = mockSetting(nockInstance, 'autosearch_while_typing');
100
+ scopeBookmark = nockInstance
101
+ .get('/api/v2/bookmarks')
102
+ .query(true)
103
+ .reply(200, {});
93
104
 
94
105
  const {
95
106
  getByText,
@@ -114,6 +125,8 @@ test('Can show latest version and link to it', async (done) => {
114
125
  });
115
126
  assertNockRequest(scopeBookmark);
116
127
  assertNockRequest(autocompleteScope);
128
+ assertNockRequest(searchDelayScope);
129
+ assertNockRequest(autoSearchScope);
117
130
  assertNockRequest(scope, done); // Pass jest callback to confirm test is done
118
131
  });
119
132
 
@@ -123,6 +136,12 @@ test('Can expand cv and show activation keys and hosts', async (done) => {
123
136
  .get(cvIndexPath)
124
137
  .query(true)
125
138
  .reply(200, cvIndexData);
139
+ searchDelayScope = mockSetting(nockInstance, 'autosearch_delay', 0);
140
+ autoSearchScope = mockSetting(nockInstance, 'autosearch_while_typing');
141
+ scopeBookmark = nockInstance
142
+ .get('/api/v2/bookmarks')
143
+ .query(true)
144
+ .reply(200, {});
126
145
 
127
146
  const {
128
147
  queryByLabelText,
@@ -152,18 +171,21 @@ test('Can expand cv and show activation keys and hosts', async (done) => {
152
171
  });
153
172
 
154
173
  assertNockRequest(autocompleteScope);
174
+ assertNockRequest(searchDelayScope);
175
+ assertNockRequest(autoSearchScope);
176
+ assertNockRequest(scopeBookmark);
155
177
  assertNockRequest(scope, done); // Pass jest callback to confirm test is done
156
178
  });
157
179
 
158
180
  test('Can handle no Content Views being present', async (done) => {
159
- const autocompleteScope = mockAutocomplete(nockInstance, autocompleteUrl);
160
-
161
181
  const noResults = {
162
182
  total: 0,
163
183
  subtotal: 0,
164
184
  page: 1,
165
185
  per_page: 20,
166
186
  results: [],
187
+ can_view: true,
188
+ can_create: true,
167
189
  };
168
190
  const scope = nockInstance
169
191
  .get(cvIndexPath)
@@ -173,12 +195,10 @@ test('Can handle no Content Views being present', async (done) => {
173
195
 
174
196
  expect(queryByText(firstCV.name)).toBeNull();
175
197
  await patientlyWaitFor(() => expect(queryByText(/don't have any Content views/i)).toBeInTheDocument());
176
- assertNockRequest(autocompleteScope);
177
198
  assertNockRequest(scope, done);
178
199
  });
179
200
 
180
201
  test('Can handle errored response', async (done) => {
181
- const autocompleteScope = mockAutocomplete(nockInstance, autocompleteUrl);
182
202
  const scope = nockInstance
183
203
  .get(cvIndexPath)
184
204
  .query(true)
@@ -188,7 +208,6 @@ test('Can handle errored response', async (done) => {
188
208
 
189
209
  expect(queryByText(firstCV.name)).toBeNull();
190
210
  await patientlyWaitFor(() => expect(queryByText(/Something went wrong! Please check server logs!/i)).toBeInTheDocument());
191
- assertNockRequest(autocompleteScope);
192
211
  assertNockRequest(scope, done);
193
212
  });
194
213
 
@@ -201,11 +220,20 @@ test('Can handle unpublished Content Views', async (done) => {
201
220
  .get(cvIndexPath)
202
221
  .query(true)
203
222
  .reply(200, unpublishedCVData);
223
+ searchDelayScope = mockSetting(nockInstance, 'autosearch_delay', 0);
224
+ autoSearchScope = mockSetting(nockInstance, 'autosearch_while_typing');
225
+ scopeBookmark = nockInstance
226
+ .get('/api/v2/bookmarks')
227
+ .query(true)
228
+ .reply(200, {});
204
229
 
205
230
  const { getAllByText } = renderWithRedux(<ContentViewsPage />, renderOptions);
206
231
 
207
232
  await patientlyWaitFor(() => expect(getAllByText(/not yet published/i).length).toBeGreaterThan(0));
208
233
  assertNockRequest(autocompleteScope);
234
+ assertNockRequest(searchDelayScope);
235
+ assertNockRequest(autoSearchScope);
236
+ assertNockRequest(scopeBookmark);
209
237
  assertNockRequest(scope, done);
210
238
  });
211
239
 
@@ -215,6 +243,12 @@ test('Can handle pagination', async (done) => {
215
243
  const cvIndexFirstPage = { ...cvIndexLarge, ...{ results: results.slice(0, 20) } };
216
244
  const cvIndexSecondPage = { ...cvIndexLarge, page: 2, results: results.slice(20, 40) };
217
245
  const autocompleteScope = mockAutocomplete(nockInstance, autocompleteUrl);
246
+ searchDelayScope = mockSetting(nockInstance, 'autosearch_delay', 0);
247
+ autoSearchScope = mockSetting(nockInstance, 'autosearch_while_typing');
248
+ scopeBookmark = nockInstance
249
+ .get('/api/v2/bookmarks')
250
+ .query(true)
251
+ .reply(200, {});
218
252
 
219
253
  // Match first page API request
220
254
  const firstPageScope = nockInstance
@@ -249,6 +283,9 @@ test('Can handle pagination', async (done) => {
249
283
  expect(queryByText(results[41].name)).not.toBeInTheDocument();
250
284
  });
251
285
  assertNockRequest(autocompleteScope);
286
+ assertNockRequest(autoSearchScope);
287
+ assertNockRequest(searchDelayScope);
288
+ assertNockRequest(scopeBookmark);
252
289
  assertNockRequest(firstPageScope);
253
290
  assertNockRequest(secondPageScope, done); // Only pass jest callback to the last API request
254
291
  });
@@ -264,6 +301,13 @@ test('Can search for specific Content View', async (done) => {
264
301
 
265
302
  const autocompleteScope = mockAutocomplete(nockInstance, autocompleteUrl);
266
303
  const withSearchScope = mockAutocomplete(nockInstance, autocompleteUrl, matchQuery);
304
+ searchDelayScope = mockSetting(nockInstance, 'autosearch_delay', 0);
305
+ autoSearchScope = mockSetting(nockInstance, 'autosearch_while_typing');
306
+ scopeBookmark = nockInstance
307
+ .get('/api/v2/bookmarks')
308
+ .query(true)
309
+ .reply(200, {});
310
+
267
311
  const initialScope = nockInstance
268
312
  .get(cvIndexPath)
269
313
  .query(true)
@@ -291,6 +335,9 @@ test('Can search for specific Content View', async (done) => {
291
335
  });
292
336
 
293
337
  assertNockRequest(autocompleteScope);
338
+ assertNockRequest(searchDelayScope);
339
+ assertNockRequest(autoSearchScope);
340
+ assertNockRequest(scopeBookmark);
294
341
  assertNockRequest(initialScope);
295
342
  assertNockRequest(withSearchScope);
296
343
  assertNockRequest(searchResultScope, done);
@@ -301,10 +348,23 @@ test('No results message is shown for empty search', async (done) => {
301
348
  const query = `name = \"${cvname}\"`;
302
349
  const matchQuery = actualParams => actualParams?.search?.includes(cvname);
303
350
  const emptyResults = {
304
- total: 0, subtotal: 0, page: 1, per_page: 20, search: query, results: [],
351
+ total: 0,
352
+ subtotal: 0,
353
+ page: 1,
354
+ per_page: 20,
355
+ search: query,
356
+ results: [],
357
+ can_view: true,
358
+ can_create: true,
305
359
  };
306
360
 
307
361
  const autocompleteScope = mockAutocomplete(nockInstance, autocompleteUrl);
362
+ searchDelayScope = mockSetting(nockInstance, 'autosearch_delay', 0);
363
+ autoSearchScope = mockSetting(nockInstance, 'autosearch_while_typing');
364
+ scopeBookmark = nockInstance
365
+ .get('/api/v2/bookmarks')
366
+ .query(true)
367
+ .reply(200, {});
308
368
  const withSearchScope = mockAutocomplete(nockInstance, autocompleteUrl, matchQuery);
309
369
  const initialScope = nockInstance
310
370
  .get(cvIndexPath)
@@ -324,20 +384,22 @@ test('No results message is shown for empty search', async (done) => {
324
384
  await patientlyWaitFor(() => expect(getByText(/No matching content views found/i)).toBeInTheDocument());
325
385
 
326
386
  assertNockRequest(autocompleteScope);
387
+ assertNockRequest(searchDelayScope);
388
+ assertNockRequest(autoSearchScope);
389
+ assertNockRequest(scopeBookmark);
327
390
  assertNockRequest(initialScope);
328
391
  assertNockRequest(withSearchScope);
329
392
  assertNockRequest(searchResultScope, done);
330
393
  });
331
394
 
332
395
  test('Displays Create Content View and opens modal with Form', async () => {
333
- mockAutocomplete(nockInstance, autocompleteUrl);
334
-
335
396
  const noResults = {
336
397
  total: 0,
337
398
  subtotal: 0,
338
399
  page: 1,
339
400
  per_page: 20,
340
401
  can_create: true,
402
+ can_view: true,
341
403
  results: [],
342
404
  };
343
405
  nockInstance
@@ -101,7 +101,7 @@ const CVBreadcrumb = () => {
101
101
  filterDetails, filterDetailsStatus, breadcrumbItems, setBreadcrumbItems]);
102
102
 
103
103
  return (
104
- <Breadcrumb className="margin-bottom-24">
104
+ <Breadcrumb ouiaId="cv-breadcrumb" className="margin-bottom-24">
105
105
  {
106
106
  Object.keys(breadcrumbItems)?.sort()?.map(key => (
107
107
  <BreadcrumbItem
@@ -58,6 +58,7 @@ const EnvironmentPaths = ({
58
58
  className="env-path__labels-with-pointer"
59
59
  key={`${env.id}${index}`}
60
60
  id={`${env.id}${index}`}
61
+ ouiaId={`${env.id}${index}`}
61
62
  label={<EnvironmentLabels environments={env} isDisabled={isDisabled} />}
62
63
  aria-label={env.label}
63
64
  onChange={checked => oncheckedChange(checked, env)}
@@ -4,7 +4,15 @@ import { TextContent, Text, TextVariants } from '@patternfly/react-core';
4
4
 
5
5
  const InactiveText = props => (
6
6
  <TextContent>
7
- <Text component={TextVariants.small} {...props}>{props.text}</Text>
7
+ <Text
8
+ ouiaId="inactive-text"
9
+ component={TextVariants.small}
10
+ style={{
11
+ display: 'inline-flex', alignItems: 'center', margin: 0,
12
+ }}
13
+ {...props}
14
+ >{props.text}
15
+ </Text>
8
16
  </TextContent>
9
17
  );
10
18
 
@@ -35,6 +35,7 @@ const RelatedCompositeContentViewsModal = ({
35
35
  </Button>
36
36
  <Modal
37
37
  title={__('Related composite content views')}
38
+ ouiaId="related-composite-cvs"
38
39
  variant={ModalVariant.large}
39
40
  isOpen={isOpen}
40
41
  description={description()}
@@ -45,10 +46,11 @@ const RelatedCompositeContentViewsModal = ({
45
46
  >
46
47
  <TableComposable
47
48
  aria-label={`${cvId}_table`}
49
+ ouiaId={`${cvId}_table`}
48
50
  variant="compact"
49
51
  >
50
52
  <Thead>
51
- <Tr>
53
+ <Tr ouiaId="table-header-row">
52
54
  {columns.map((column, columnIndex) => (
53
55
  <Th key={columnIndex}>{column}</Th>
54
56
  ))}
@@ -56,7 +58,7 @@ const RelatedCompositeContentViewsModal = ({
56
58
  </Thead>
57
59
  <Tbody>
58
60
  {relatedCompositeCVs.map(cv => (
59
- <Tr key={cv.id}>
61
+ <Tr key={cv.id} ouiaId={`row-${cv.id}`}>
60
62
  <Td key={`${cv.id}_${cv.name}`} dataLabel={columns[cv.id]}>
61
63
  <Link to={`${urlBuilder('content_views', '')}${cv.id}`}>{cv.name}</Link>
62
64
  </Td>
@@ -50,6 +50,7 @@ const RelatedContentViewsModal = ({ cvName, cvId, relatedCVCount }) => {
50
50
  <GridItem span={12}>
51
51
  <Modal
52
52
  title={__('Related content views')}
53
+ ouiaId="related-cvs"
53
54
  variant={ModalVariant.medium}
54
55
  isOpen={isOpen}
55
56
  description={description()}
@@ -76,13 +77,13 @@ const RelatedContentViewsModal = ({ cvName, cvId, relatedCVCount }) => {
76
77
  emptySearchBody={__('Try changing your search settings.')}
77
78
  >
78
79
  <Thead>
79
- <Tr>
80
+ <Tr ouiaId="column-headers">
80
81
  <Th key="name_col">{__('Name')}</Th>
81
82
  </Tr>
82
83
  </Thead>
83
84
  <Tbody>
84
85
  {results?.map(details => (
85
- <Tr key={`${details.content_view.id}`}>
86
+ <Tr key={`${details.content_view.id}`} ouiaId={`${details.content_view.id}`}>
86
87
  <Td>
87
88
  <Link to={urlBuilder(`content_views/${details.content_view.id}`, '')}>{details.content_view.name}</Link>
88
89
  </Td>
@@ -3,19 +3,19 @@ import { foremanUrl } from 'foremanReact/common/helpers';
3
3
  import { get, post, put } from 'foremanReact/redux/API';
4
4
  import { translate as __ } from 'foremanReact/common/I18n';
5
5
 
6
- import { CHANGE_CONTENT_SOURCE_DATA,
6
+ import {
7
+ CHANGE_CONTENT_SOURCE_DATA,
8
+ CHANGE_CONTENT_SOURCE_PROXY,
7
9
  CHANGE_CONTENT_SOURCE,
8
- CHANGE_CONTENT_SOURCE_VIEWS } from './constants';
10
+ CHANGE_CONTENT_SOURCE_VIEWS,
11
+ } from './constants';
9
12
 
10
- import { getHostIds } from './helpers';
11
-
12
- export const getFormData = () =>
13
- post({
14
- key: CHANGE_CONTENT_SOURCE_DATA,
15
- url: foremanUrl('/change_host_content_source/data'),
16
- params: { host_ids: getHostIds() },
17
- errorToast: () => __('Something went wrong while getting the data. See the logs for more information'),
18
- });
13
+ export const getFormData = (hostIds, search) => (post({
14
+ key: CHANGE_CONTENT_SOURCE_DATA,
15
+ url: foremanUrl('/change_host_content_source/data'),
16
+ params: { host_ids: hostIds, search },
17
+ errorToast: () => __('Something went wrong while getting the data. See the logs for more information'),
18
+ }));
19
19
 
20
20
  export const changeContentSource = (environmentId, contentViewId, contentSourceId, hostIds) =>
21
21
  put({
@@ -31,6 +31,13 @@ export const changeContentSource = (environmentId, contentViewId, contentSourceI
31
31
  errorToast: () => __('Something went wrong while updating the content source. See the logs for more information'),
32
32
  });
33
33
 
34
+ export const getProxy = id =>
35
+ get({
36
+ key: CHANGE_CONTENT_SOURCE_PROXY,
37
+ url: foremanUrl(`/katello/api/capsules/${id}`),
38
+ errorToast: () => __('Something went wrong while loading the Smart Proxy. See the logs for more information'),
39
+ });
40
+
34
41
  export const getContentViews = environmentId =>
35
42
  get({
36
43
  key: CHANGE_CONTENT_SOURCE_VIEWS,
@@ -22,13 +22,20 @@ const ContentSourceForm = ({
22
22
  contentSources,
23
23
  handleContentSource,
24
24
  contentSourceId,
25
- contentHostsIds,
25
+ contentHosts,
26
26
  isLoading,
27
27
  }) => {
28
28
  const formIsValid = () => (!!environmentId &&
29
29
  !!contentViewId &&
30
30
  !!contentSourceId &&
31
- contentHostsIds.length !== 0);
31
+ contentHosts.length !== 0);
32
+
33
+ const contentSourcesIsDisabled = (isLoading || contentSources.length === 0 ||
34
+ contentHosts.length === 0);
35
+ const environmentIsDisabled = (isLoading || environments.length === 0 ||
36
+ contentSourceId === '');
37
+ const viewIsDisabled = (isLoading || contentViews.length === 0 ||
38
+ contentSourceId === '' || environmentId === '');
32
39
 
33
40
  return (
34
41
  <Form
@@ -36,10 +43,10 @@ const ContentSourceForm = ({
36
43
  className="content_source_form"
37
44
  isHorizontal
38
45
  >
39
- <Grid hasGutter>
40
- <FormField label={__('Environment')} id="change_cs_environment" value={environmentId} items={environments} onChange={handleEnvironment} isLoading={isLoading} contentHostsCount={contentHostsIds.length} />
41
- <FormField label={__('Content View')} id="change_cs_content_view" value={contentViewId} items={contentViews} onChange={handleContentView} isLoading={isLoading} contentHostsCount={contentHostsIds.length} />
42
- <FormField label={__('Content Source')} id="change_cs_content_source" value={contentSourceId} items={contentSources} onChange={handleContentSource} isLoading={isLoading} contentHostsCount={contentHostsIds.length} />
46
+ <Grid hasGutter className="margin-top-16">
47
+ <FormField label={__('Content source')} id="change_cs_content_source" value={contentSourceId} items={contentSources} onChange={handleContentSource} isDisabled={contentSourcesIsDisabled} />
48
+ <FormField label={__('Environment')} id="change_cs_environment" value={environmentId} items={environments} onChange={handleEnvironment} isDisabled={environmentIsDisabled} />
49
+ <FormField label={__('Content view')} id="change_cs_content_view" value={contentViewId} items={contentViews} onChange={handleContentView} isDisabled={viewIsDisabled} />
43
50
 
44
51
  <GridItem>
45
52
  <ActionGroup>
@@ -69,7 +76,7 @@ ContentSourceForm.propTypes = {
69
76
  contentSources: PropTypes.arrayOf(PropTypes.shape({})),
70
77
  handleContentSource: PropTypes.func.isRequired,
71
78
  contentSourceId: PropTypes.string,
72
- contentHostsIds: PropTypes.arrayOf(PropTypes.number),
79
+ contentHosts: PropTypes.arrayOf(PropTypes.shape({})),
73
80
  isLoading: PropTypes.bool,
74
81
  };
75
82
 
@@ -80,7 +87,7 @@ ContentSourceForm.defaultProps = {
80
87
  contentViewId: '',
81
88
  contentSources: [],
82
89
  contentSourceId: '',
83
- contentHostsIds: [],
90
+ contentHosts: [],
84
91
  isLoading: false,
85
92
  };
86
93
 
@@ -9,7 +9,7 @@ import { translate as __ } from 'foremanReact/common/I18n';
9
9
  import PropTypes from 'prop-types';
10
10
 
11
11
  const FormField = ({
12
- label, id, value, items, onChange, isLoading, contentHostsCount,
12
+ label, id, value, items, onChange, isDisabled,
13
13
  }) => (
14
14
  <GridItem span={7}>
15
15
  <FormGroup label={label} fieldId={id} isRequired>
@@ -17,7 +17,7 @@ const FormField = ({
17
17
  value={value}
18
18
  onChange={v => onChange(v)}
19
19
  className="without_select2"
20
- isDisabled={isLoading || items.length === 0 || contentHostsCount === 0}
20
+ isDisabled={isDisabled}
21
21
  id={`${id}_select`}
22
22
  isRequired
23
23
  >
@@ -36,8 +36,7 @@ FormField.propTypes = {
36
36
  value: PropTypes.string.isRequired,
37
37
  items: PropTypes.arrayOf(PropTypes.shape({})).isRequired,
38
38
  onChange: PropTypes.func.isRequired,
39
- isLoading: PropTypes.bool.isRequired,
40
- contentHostsCount: PropTypes.number.isRequired,
39
+ isDisabled: PropTypes.bool.isRequired,
41
40
  };
42
41
 
43
42
  export default FormField;
@@ -0,0 +1,55 @@
1
+ import React, { useState } from 'react';
2
+ import {
3
+ GridItem,
4
+ Label,
5
+ } from '@patternfly/react-core';
6
+
7
+ import { translate as __ } from 'foremanReact/common/I18n';
8
+ import PropTypes from 'prop-types';
9
+
10
+ import HostsModal from './HostsModal';
11
+
12
+ const Hosts = ({
13
+ contentHosts, hostsWithoutContent,
14
+ }) => {
15
+ const [modalHosts, setModalHosts] = useState(false);
16
+ const [modalIgnored, setModalIgnored] = useState(false);
17
+
18
+ const titleHosts = __('Hosts to update');
19
+ const titleIgnored = __('Ignored hosts');
20
+
21
+ return (
22
+ <>
23
+ <GridItem span={7}>
24
+ {hostsWithoutContent.length > 0 &&
25
+ <p>
26
+ { __('Some hosts are not registered as content hosts and will be ignored.') }
27
+ </p>
28
+ }
29
+ {contentHosts.length > 0 && (<Label color="green" href="#" onClick={() => setModalHosts(true)}>{titleHosts}: {contentHosts.length}</Label>)}
30
+ {' '}
31
+ {hostsWithoutContent.length > 0 && (<Label color="orange" href="#" onClick={() => setModalIgnored(true)}>{titleIgnored}: {hostsWithoutContent.length}</Label>)}
32
+
33
+ <HostsModal
34
+ hosts={contentHosts}
35
+ isOpen={modalHosts}
36
+ setModalOpenState={setModalHosts}
37
+ modalTitle={titleHosts}
38
+ />
39
+ <HostsModal
40
+ hosts={hostsWithoutContent}
41
+ isOpen={modalIgnored}
42
+ setModalOpenState={setModalIgnored}
43
+ modalTitle={titleIgnored}
44
+ />
45
+ </GridItem>
46
+ </>
47
+ );
48
+ };
49
+
50
+ Hosts.propTypes = {
51
+ contentHosts: PropTypes.arrayOf(PropTypes.shape({})).isRequired,
52
+ hostsWithoutContent: PropTypes.arrayOf(PropTypes.shape({})).isRequired,
53
+ };
54
+
55
+ export default Hosts;
@@ -0,0 +1,59 @@
1
+ import React, { useState } from 'react';
2
+ import {
3
+ Button,
4
+ Modal,
5
+ ModalVariant,
6
+ List, ListItem,
7
+ SearchInput,
8
+ } from '@patternfly/react-core';
9
+
10
+ import { translate as __ } from 'foremanReact/common/I18n';
11
+ import { foremanUrl } from 'foremanReact/common/helpers';
12
+
13
+ import PropTypes from 'prop-types';
14
+
15
+ const HostsModal = ({
16
+ hosts, isOpen, setModalOpenState, modalTitle,
17
+ }) => {
18
+ const [search, setSearch] = useState('');
19
+
20
+ return (
21
+ <Modal
22
+ variant={ModalVariant.small}
23
+ title={modalTitle}
24
+ position="top"
25
+ isOpen={isOpen}
26
+ onClose={() => setModalOpenState(false)}
27
+ >
28
+ <SearchInput
29
+ placeholder={__('Search')}
30
+ value={search}
31
+ onChange={v => setSearch(v)}
32
+ onClear={() => setSearch('')}
33
+ />
34
+ <List isPlain isBordered className="margin-top-16">
35
+ {(search ? hosts.filter(h => (`${h.name}`).includes(search)) : hosts).map(h => (
36
+ <ListItem key={h.id}>
37
+ <Button
38
+ component="a"
39
+ href={foremanUrl(`/new/hosts/${h.name}`)}
40
+ variant="link"
41
+ target="_blank"
42
+ isInline
43
+ >
44
+ {h.name}
45
+ </Button>
46
+ </ListItem>
47
+ ))}
48
+ </List>
49
+ </Modal>);
50
+ };
51
+
52
+ HostsModal.propTypes = {
53
+ hosts: PropTypes.arrayOf(PropTypes.shape({})).isRequired,
54
+ isOpen: PropTypes.bool.isRequired,
55
+ setModalOpenState: PropTypes.func.isRequired,
56
+ modalTitle: PropTypes.string.isRequired,
57
+ };
58
+
59
+ export default HostsModal;
@@ -1,3 +1,4 @@
1
1
  export const CHANGE_CONTENT_SOURCE_DATA = 'CHANGE_CONTENT_SOURCE_DATA';
2
+ export const CHANGE_CONTENT_SOURCE_PROXY = 'CHANGE_CONTENT_SOURCE_PROXY';
2
3
  export const CHANGE_CONTENT_SOURCE = 'CHANGE_CONTENT_SOURCE';
3
4
  export const CHANGE_CONTENT_SOURCE_VIEWS = 'CHANGE_CONTENT_SOURCE_VIEWS';