katello 4.3.0 → 4.4.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 (337) 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/api_controller.rb +13 -4
  4. data/app/controllers/katello/api/v2/content_view_versions_controller.rb +3 -0
  5. data/app/controllers/katello/api/v2/content_views_controller.rb +46 -0
  6. data/app/controllers/katello/api/v2/host_packages_controller.rb +21 -1
  7. data/app/controllers/katello/api/v2/hosts_bulk_actions_controller.rb +30 -1
  8. data/app/controllers/katello/api/v2/organizations_controller.rb +10 -6
  9. data/app/controllers/katello/api/v2/packages_controller.rb +4 -0
  10. data/app/controllers/katello/api/v2/repositories_controller.rb +17 -7
  11. data/app/controllers/katello/api/v2/repository_sets_controller.rb +7 -0
  12. data/app/controllers/katello/concerns/api/v2/repository_content_controller.rb +3 -0
  13. data/app/controllers/katello/concerns/hosts_controller_extensions.rb +32 -0
  14. data/app/controllers/katello/remote_execution_controller.rb +5 -4
  15. data/app/helpers/katello/content_source_helper.rb +43 -0
  16. data/app/helpers/katello/hosts_and_hostgroups_helper.rb +4 -0
  17. data/app/lib/actions/katello/cdn_configuration/update.rb +5 -7
  18. data/app/lib/actions/katello/content_view/publish.rb +5 -0
  19. data/app/lib/actions/katello/content_view_version/incremental_update.rb +17 -3
  20. data/app/lib/actions/katello/repository/discover.rb +1 -14
  21. data/app/lib/actions/katello/repository/filtered_index_content.rb +1 -1
  22. data/app/lib/actions/pulp3/content_view_version/import.rb +7 -0
  23. data/app/lib/actions/pulp3/orchestration/content_view_version/import.rb +7 -5
  24. data/app/lib/actions/pulp3/repository/copy_content.rb +1 -1
  25. data/app/lib/actions/pulp3/repository/save_artifact.rb +1 -0
  26. data/app/lib/katello/concerns/base_template_scope_extensions.rb +11 -0
  27. data/app/lib/katello/errors.rb +3 -3
  28. data/app/lib/katello/logging.rb +6 -1
  29. data/app/lib/katello/repo_discovery.rb +27 -19
  30. data/app/lib/katello/resources/cdn/katello_cdn.rb +41 -3
  31. data/app/lib/katello/resources/cdn.rb +4 -2
  32. data/app/lib/katello/util/deduplication_migrator.rb +105 -0
  33. data/app/models/katello/candlepin/repository_mapper.rb +1 -1
  34. data/app/models/katello/cdn_configuration.rb +38 -6
  35. data/app/models/katello/concerns/host_managed_extensions.rb +23 -1
  36. data/app/models/katello/concerns/organization_extensions.rb +5 -1
  37. data/app/models/katello/concerns/pulp_database_unit.rb +59 -173
  38. data/app/models/katello/concerns/remote_execution_proxy_selector_extensions.rb +11 -0
  39. data/app/models/katello/concerns/smart_proxy_extensions.rb +1 -1
  40. data/app/models/katello/content_view.rb +4 -4
  41. data/app/models/katello/content_view_filter.rb +1 -1
  42. data/app/models/katello/content_view_history.rb +1 -1
  43. data/app/models/katello/content_view_version.rb +6 -2
  44. data/app/models/katello/content_view_version_export_history.rb +1 -1
  45. data/app/models/katello/deb.rb +1 -3
  46. data/app/models/katello/docker_meta_tag.rb +1 -1
  47. data/app/models/katello/erratum.rb +0 -15
  48. data/app/models/katello/glue/pulp/repos.rb +1 -1
  49. data/app/models/katello/host/content_facet.rb +2 -27
  50. data/app/models/katello/host/info_provider.rb +9 -0
  51. data/app/models/katello/host/subscription_facet.rb +2 -2
  52. data/app/models/katello/hostgroup/content_facet.rb +2 -2
  53. data/app/models/katello/product.rb +1 -1
  54. data/app/models/katello/product_content.rb +2 -2
  55. data/app/models/katello/repository.rb +10 -9
  56. data/app/models/katello/root_repository.rb +24 -13
  57. data/app/models/katello/rpm.rb +8 -2
  58. data/app/models/setting/content.rb +6 -3
  59. data/app/services/cert/rhsm_client.rb +1 -5
  60. data/app/services/katello/content_unit_indexer.rb +166 -0
  61. data/app/services/katello/organization_creator.rb +12 -4
  62. data/app/services/katello/pulp/repository/docker.rb +1 -1
  63. data/app/services/katello/pulp/repository/yum.rb +0 -54
  64. data/app/services/katello/pulp/repository.rb +0 -6
  65. data/app/services/katello/pulp3/ansible_collection.rb +26 -10
  66. data/app/services/katello/pulp3/api/apt.rb +7 -0
  67. data/app/services/katello/pulp3/content_view_version/import.rb +11 -2
  68. data/app/services/katello/pulp3/deb.rb +10 -9
  69. data/app/services/katello/pulp3/docker_manifest.rb +6 -5
  70. data/app/services/katello/pulp3/docker_manifest_list.rb +23 -6
  71. data/app/services/katello/pulp3/docker_tag.rb +16 -7
  72. data/app/services/katello/pulp3/erratum.rb +51 -56
  73. data/app/services/katello/pulp3/file_unit.rb +9 -6
  74. data/app/services/katello/pulp3/generic_content_unit.rb +11 -12
  75. data/app/services/katello/pulp3/module_stream.rb +76 -30
  76. data/app/services/katello/pulp3/package_group.rb +5 -5
  77. data/app/services/katello/pulp3/pulp_content_unit.rb +19 -11
  78. data/app/services/katello/pulp3/repository/apt.rb +5 -3
  79. data/app/services/katello/pulp3/repository/docker.rb +14 -7
  80. data/app/services/katello/pulp3/repository/generic.rb +1 -1
  81. data/app/services/katello/pulp3/repository/yum.rb +10 -12
  82. data/app/services/katello/pulp3/repository.rb +26 -7
  83. data/app/services/katello/pulp3/repository_mirror.rb +18 -5
  84. data/app/services/katello/pulp3/rpm.rb +13 -13
  85. data/app/services/katello/pulp3/srpm.rb +10 -9
  86. data/app/services/katello/repository_type.rb +15 -4
  87. data/app/services/katello/repository_type_manager.rb +1 -1
  88. data/app/services/katello/ui_notifications/subscriptions/manifest_expired_warning.rb +1 -1
  89. data/app/services/katello/upstream_connection_checker.rb +2 -2
  90. data/app/views/foreman/job_templates/change_content_source.erb +1 -31
  91. data/app/views/foreman/job_templates/install_errata.erb +6 -9
  92. data/app/views/foreman/job_templates/install_errata_by_search_query.erb +26 -0
  93. data/app/views/foreman/job_templates/install_packages_by_search_query.erb +19 -0
  94. data/app/views/katello/api/v2/cdn_configurations/show.json.rabl +1 -1
  95. data/app/views/katello/api/v2/environments/show.json.rabl +9 -0
  96. data/app/views/katello/api/v2/repositories/show.json.rabl +2 -0
  97. data/app/views/katello/layouts/react.html.erb +0 -1
  98. data/app/views/katello/sync_management/_repo.html.erb +36 -25
  99. data/config/initializers/monkeys.rb +0 -1
  100. data/config/routes/api/v2.rb +1 -0
  101. data/config/routes/overrides.rb +3 -0
  102. data/config/routes.rb +2 -0
  103. data/db/migrate/20150930183738_migrate_content_hosts.rb +1 -1
  104. data/db/migrate/20180612164926_add_content_org_id.rb +2 -2
  105. data/db/migrate/20211201154845_add_unique_indexes.rb +20 -0
  106. data/db/migrate/20211208034230_add_content_view_and_lifecycle_environment.rb +6 -0
  107. data/db/migrate/20211220185935_clean_duplicate_content_units.rb +144 -0
  108. data/db/migrate/20220110223754_update_disconnected_settings.rb +20 -0
  109. data/db/migrate/20220120163252_fix_docker_download_policy.rb +11 -0
  110. data/db/migrate/20220124191056_add_type_to_cdn_configuration.rb +22 -0
  111. data/db/migrate/20220127120843_fix_debian_download_policy.rb +11 -0
  112. data/db/migrate/20220204171908_rename_docker_tags_whitelist_and_add_exclude_tags.rb +8 -0
  113. data/db/migrate/20220207140355_change_deb_attributes_size_limit.rb +7 -0
  114. data/db/seeds.d/111-upgrade_tasks.rb +2 -1
  115. data/engines/bastion/app/views/bastion/layouts/application.html.erb +0 -1
  116. data/engines/bastion/app/views/bastion/layouts/assets.html.erb +0 -1
  117. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/content-credentials/content-credentials.controller.js +1 -1
  118. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/content-credentials/details/content-credential-products.controller.js +1 -1
  119. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/content-credentials/details/content-credential-repositories.controller.js +1 -1
  120. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/content-hosts/bulk/views/content-hosts-bulk-traces-modal.html +1 -1
  121. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/environments/details/views/environment.html +26 -1
  122. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/i18n/bastion_katello.pot +212 -152
  123. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/packages/packages.controller.js +1 -0
  124. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/products/details/repositories/details/repository-details-info.controller.js +20 -8
  125. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/products/details/repositories/details/repository-details-manage-content.controller.js +2 -3
  126. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/products/details/repositories/details/repository-details.controller.js +8 -3
  127. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/products/details/repositories/details/views/repository-info.html +34 -30
  128. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/products/details/repositories/new/new-repository.controller.js +16 -2
  129. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/products/details/repositories/new/views/new-repository.html +35 -15
  130. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/products/discovery/discovery.controller.js +5 -4
  131. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/products/products.routes.js +4 -3
  132. data/lib/katello/engine.rb +4 -0
  133. data/lib/katello/permission_creator.rb +1 -1
  134. data/lib/katello/permissions/host_permissions.rb +3 -1
  135. data/lib/katello/plugin.rb +4 -1
  136. data/lib/katello/repository_types/deb.rb +0 -1
  137. data/lib/katello/repository_types/docker.rb +4 -4
  138. data/lib/katello/repository_types/file.rb +0 -1
  139. data/lib/katello/repository_types/ostree.rb +4 -0
  140. data/lib/katello/repository_types/python.rb +5 -1
  141. data/lib/katello/repository_types/yum.rb +2 -9
  142. data/lib/katello/tasks/content_view_import_only.rake +34 -0
  143. data/lib/katello/tasks/import_applicability.rake +1 -1
  144. data/lib/katello/tasks/jenkins.rake +0 -2
  145. data/lib/katello/tasks/repository.rake +4 -1
  146. data/lib/katello/tasks/upgrades/4.4/publish_import_cvvs.rake +17 -0
  147. data/lib/katello/version.rb +1 -1
  148. data/locale/action_names.rb +8 -7
  149. data/locale/bn/katello.po +1402 -650
  150. data/locale/cs/katello.po +1217 -96
  151. data/locale/de/katello.po +2359 -1347
  152. data/locale/en/katello.po +1216 -94
  153. data/locale/es/katello.po +2201 -1172
  154. data/locale/fr/katello.po +2601 -1615
  155. data/locale/gu/katello.po +1564 -814
  156. data/locale/hi/katello.po +1563 -810
  157. data/locale/it/katello.po +1311 -282
  158. data/locale/ja/katello.po +2534 -1518
  159. data/locale/katello.pot +3430 -1326
  160. data/locale/kn/katello.po +1564 -812
  161. data/locale/ko/katello.po +1441 -409
  162. data/locale/mr/katello.po +1564 -776
  163. data/locale/or/katello.po +1565 -813
  164. data/locale/pa/katello.po +1559 -792
  165. data/locale/pt/katello.po +1314 -277
  166. data/locale/pt_BR/katello.po +2226 -1181
  167. data/locale/ru/katello.po +1587 -563
  168. data/locale/ta/katello.po +1373 -619
  169. data/locale/te/katello.po +1564 -810
  170. data/locale/zh_CN/katello.po +2936 -1890
  171. data/locale/zh_TW/katello.po +1508 -606
  172. data/webpack/__mocks__/foremanReact/{redux/actions/toasts.js → components/ToastsList/index.js} +3 -2
  173. data/webpack/components/ActionableDetail.js +35 -21
  174. data/webpack/components/Content/Details/__tests__/ContentDetailInfo.test.js +0 -2
  175. data/webpack/components/Content/Details/__tests__/ContentDetailRepositories.test.js +0 -2
  176. data/webpack/components/Content/Details/__tests__/ContentDetails.test.js +0 -2
  177. data/webpack/components/Content/__tests__/ContentPage.test.js +0 -2
  178. data/webpack/components/Content/__tests__/ContentTable.test.js +0 -2
  179. data/webpack/components/EditableSwitch.js +8 -2
  180. data/webpack/components/EditableTextInput/EditableTextInput.js +44 -86
  181. data/webpack/components/EditableTextInput/__tests__/editableTextInput.test.js +3 -3
  182. data/webpack/components/Errata/index.js +19 -11
  183. data/webpack/components/Packages/index.js +1 -1
  184. data/webpack/components/Search/Search.js +5 -2
  185. data/webpack/components/Search/__tests__/search.test.js +2 -3
  186. data/webpack/components/SelectOrg/SetOrganization.js +1 -1
  187. data/webpack/components/Table/PageControls.js +3 -6
  188. data/webpack/components/Table/TableHooks.js +46 -7
  189. data/webpack/components/Table/TableWrapper.js +14 -3
  190. data/webpack/components/TypeAhead/TypeAhead.js +5 -1
  191. data/webpack/components/TypeAhead/pf4Search/TypeAheadInput.js +4 -1
  192. data/webpack/components/TypeAhead/pf4Search/TypeAheadSearch.js +2 -1
  193. data/webpack/components/extensions/HostDetails/Cards/ContentViewDetailsCard.js +1 -1
  194. data/webpack/components/extensions/HostDetails/Cards/ErrataOverviewCard.js +3 -4
  195. data/webpack/components/extensions/HostDetails/HostDetailsActions.js +2 -0
  196. data/webpack/components/extensions/HostDetails/HostPackages/HostPackagesActions.js +18 -2
  197. data/webpack/components/extensions/HostDetails/HostPackages/HostPackagesConstants.js +12 -0
  198. data/webpack/components/extensions/HostDetails/Tabs/ContentTab/SecondaryTabsRoutes.js +1 -1
  199. data/webpack/components/extensions/HostDetails/Tabs/{ErrataTab.js → ErrataTab/ErrataTab.js} +30 -21
  200. data/webpack/components/extensions/HostDetails/Tabs/{ErrataTab.scss → ErrataTab/ErrataTab.scss} +0 -0
  201. data/webpack/components/extensions/HostDetails/Tabs/{ErratumExpansionContents.js → ErrataTab/ErratumExpansionContents.js} +0 -0
  202. data/webpack/components/extensions/HostDetails/Tabs/{ErratumExpansionDetail.js → ErrataTab/ErratumExpansionDetail.js} +0 -0
  203. data/webpack/components/extensions/HostDetails/{HostErrata → Tabs/ErrataTab}/HostErrataActions.js +3 -3
  204. data/webpack/components/extensions/HostDetails/{HostErrata → Tabs/ErrataTab}/HostErrataConstants.js +11 -0
  205. data/webpack/components/extensions/HostDetails/{HostErrata → Tabs/ErrataTab}/HostErrataSelectors.js +0 -0
  206. data/webpack/components/extensions/HostDetails/Tabs/PackageInstallModal.js +279 -0
  207. data/webpack/components/extensions/HostDetails/Tabs/PackageInstallModal.scss +3 -0
  208. data/webpack/components/extensions/HostDetails/Tabs/PackagesTab.js +125 -8
  209. data/webpack/components/extensions/HostDetails/Tabs/RemoteExecutionActions.js +27 -4
  210. data/webpack/components/extensions/HostDetails/Tabs/RemoteExecutionConstants.js +2 -1
  211. data/webpack/components/extensions/HostDetails/Tabs/RepositorySetsTab/RepositorySetsTab.js +6 -3
  212. data/webpack/components/extensions/HostDetails/Tabs/{EnableTracerEmptyState.js → TracesTab/EnableTracerEmptyState.js} +0 -0
  213. data/webpack/components/extensions/HostDetails/Tabs/{EnableTracerModal.js → TracesTab/EnableTracerModal.js} +3 -2
  214. data/webpack/components/extensions/HostDetails/Tabs/{HostTracesActions.js → TracesTab/HostTracesActions.js} +2 -2
  215. data/webpack/components/extensions/HostDetails/Tabs/{HostTracesConstants.js → TracesTab/HostTracesConstants.js} +0 -0
  216. data/webpack/components/extensions/HostDetails/Tabs/{HostTracesSelectors.js → TracesTab/HostTracesSelectors.js} +0 -0
  217. data/webpack/components/extensions/HostDetails/Tabs/{TracesTab.js → TracesTab/TracesTab.js} +8 -5
  218. data/webpack/components/extensions/HostDetails/Tabs/{TracesTab.scss → TracesTab/TracesTab.scss} +0 -0
  219. data/webpack/components/extensions/HostDetails/Tabs/__tests__/errataTab.test.js +17 -18
  220. data/webpack/components/extensions/HostDetails/Tabs/__tests__/packageInstallModal.test.js +385 -0
  221. data/webpack/components/extensions/HostDetails/Tabs/__tests__/packages.fixtures.json +1 -1
  222. data/webpack/components/extensions/HostDetails/Tabs/__tests__/packagesTab.test.js +58 -7
  223. data/webpack/components/extensions/HostDetails/Tabs/__tests__/repositorySetsTab.test.js +2 -2
  224. data/webpack/components/extensions/HostDetails/Tabs/__tests__/tracesTab.test.js +4 -4
  225. data/webpack/components/extensions/HostDetails/Tabs/__tests__/yumInstallablePackages.fixtures.json +72 -0
  226. data/webpack/components/extensions/HostDetails/Tabs/customizedRexUrlHelpers.js +12 -5
  227. data/webpack/components/extensions/HostDetails/YumInstallablePackages/YumInstallablePackagesActions.js +18 -0
  228. data/webpack/components/extensions/HostDetails/YumInstallablePackages/YumInstallablePackagesConstants.js +3 -0
  229. data/webpack/components/extensions/HostDetails/YumInstallablePackages/YumInstallablePackagesSelectors.js +16 -0
  230. data/webpack/components/extensions/HostDetails/hostDetailsHelpers.js +19 -0
  231. data/webpack/components/pf3Table/components/Table.js +2 -3
  232. data/webpack/components/pf3Table/components/Table.test.js +0 -3
  233. data/webpack/components/pf3Table/components/__snapshots__/Table.test.js.snap +9 -8
  234. data/webpack/containers/Application/config.js +5 -0
  235. data/webpack/global_index.js +1 -1
  236. data/webpack/global_test_setup.js +1 -1
  237. data/webpack/index.js +7 -0
  238. data/webpack/scenes/AnsibleCollections/Details/__tests__/AnsibleCollectionDetails.test.js +0 -2
  239. data/webpack/scenes/AnsibleCollections/__tests__/AnsibleCollectionPage.test.js +0 -2
  240. data/webpack/scenes/AnsibleCollections/__tests__/AnsibleCollectionsTable.test.js +0 -2
  241. data/webpack/scenes/Content/ContentConfig.js +55 -5
  242. data/webpack/scenes/Content/ContentPage.js +1 -1
  243. data/webpack/scenes/Content/Details/ContentDetails.js +1 -1
  244. data/webpack/scenes/Content/Details/ContentInfo.js +1 -1
  245. data/webpack/scenes/Content/Details/ContentRepositories.js +1 -1
  246. data/webpack/scenes/Content/Details/__tests__/contentDetail.test.js +4 -4
  247. data/webpack/scenes/Content/Table/ContentTable.js +1 -1
  248. data/webpack/scenes/Content/__tests__/contentTable.test.js +3 -3
  249. data/webpack/scenes/ContentViews/ContentViewsConstants.js +2 -1
  250. data/webpack/scenes/ContentViews/Delete/__tests__/contentViewDelete.test.js +6 -6
  251. data/webpack/scenes/ContentViews/Details/ComponentContentViews/__tests__/contentViewComponents.test.js +2 -2
  252. data/webpack/scenes/ContentViews/Details/ContentViewDetailActions.js +21 -27
  253. data/webpack/scenes/ContentViews/Details/ContentViewDetailSelectors.js +5 -5
  254. data/webpack/scenes/ContentViews/Details/ContentViewInfo.js +8 -3
  255. data/webpack/scenes/ContentViews/Details/DetailsContainer.js +11 -16
  256. data/webpack/scenes/ContentViews/Details/Filters/ContentViewFilterDetails.js +2 -2
  257. data/webpack/scenes/ContentViews/Details/Filters/ContentViewFilterDetailsHeader.js +14 -8
  258. data/webpack/scenes/ContentViews/Details/Filters/MatchContentModal/__tests__/CVRpmMatchContentModal.test.js +2 -2
  259. data/webpack/scenes/ContentViews/Details/Filters/__tests__/CVContainerImageFilterContent.test.js +2 -3
  260. data/webpack/scenes/ContentViews/Details/Filters/__tests__/CVRpmFilterContent.test.js +2 -9
  261. data/webpack/scenes/ContentViews/Details/Filters/__tests__/contentViewFilterDetails.test.js +3 -5
  262. data/webpack/scenes/ContentViews/Details/Filters/__tests__/contentViewFilters.test.js +2 -10
  263. data/webpack/scenes/ContentViews/Details/Filters/__tests__/cvErrataIDFilter.test.js +2 -3
  264. data/webpack/scenes/ContentViews/Details/Filters/__tests__/cvModuleStreamFilter.test.js +2 -3
  265. data/webpack/scenes/ContentViews/Details/Histories/__tests__/contentViewHistory.test.js +2 -2
  266. data/webpack/scenes/ContentViews/Details/Repositories/ContentCounts.js +1 -1
  267. data/webpack/scenes/ContentViews/Details/Repositories/ContentViewRepositories.js +23 -2
  268. data/webpack/scenes/ContentViews/Details/Repositories/__tests__/contentViewAddRemove.test.js +11 -5
  269. data/webpack/scenes/ContentViews/Details/Versions/ContentViewVersionContent.js +16 -17
  270. data/webpack/scenes/ContentViews/Details/Versions/ContentViewVersions.js +1 -1
  271. data/webpack/scenes/ContentViews/Details/Versions/Delete/__tests__/cvVersionRemove.test.js +6 -6
  272. data/webpack/scenes/ContentViews/Details/Versions/VersionDetails/ContentViewVersionDetailConfig.js +30 -34
  273. data/webpack/scenes/ContentViews/Details/Versions/VersionDetails/ContentViewVersionDetails.js +9 -8
  274. data/webpack/scenes/ContentViews/Details/Versions/VersionDetails/ContentViewVersionDetailsHeader.js +13 -15
  275. data/webpack/scenes/ContentViews/Details/Versions/VersionDetails/ContentViewVersionRepositoryCell.js +1 -1
  276. data/webpack/scenes/ContentViews/Details/Versions/VersionDetails/__tests__/ContentViewVersionDetails.test.js +4 -4
  277. data/webpack/scenes/ContentViews/Details/Versions/__tests__/contentViewVersions.test.js +3 -3
  278. data/webpack/scenes/ContentViews/Details/__tests__/contentViewDetail.test.js +5 -3
  279. data/webpack/scenes/ContentViews/__tests__/contentViewPage.test.js +2 -2
  280. data/webpack/scenes/Hosts/ChangeContentSource/actions.js +43 -0
  281. data/webpack/scenes/Hosts/ChangeContentSource/components/ContentSourceForm.js +87 -0
  282. data/webpack/scenes/Hosts/ChangeContentSource/components/ContentSourceTemplate.js +90 -0
  283. data/webpack/scenes/Hosts/ChangeContentSource/components/FormField.js +43 -0
  284. data/webpack/scenes/Hosts/ChangeContentSource/constants.js +3 -0
  285. data/webpack/scenes/Hosts/ChangeContentSource/helpers.js +27 -0
  286. data/webpack/scenes/Hosts/ChangeContentSource/index.js +126 -0
  287. data/webpack/scenes/Hosts/ChangeContentSource/selectors.js +42 -0
  288. data/webpack/scenes/Hosts/ChangeContentSource/styles.scss +11 -0
  289. data/webpack/scenes/ModuleStreams/Details/Profiles/__tests__/ModuleStreamDetailProfiles.test.js +0 -1
  290. data/webpack/scenes/ModuleStreams/Details/__tests__/ModuleStreamDetails.test.js +0 -2
  291. data/webpack/scenes/ModuleStreams/__tests__/ModuleStreamPage.test.js +0 -2
  292. data/webpack/scenes/ModuleStreams/__tests__/ModuleStreamsTable.test.js +0 -2
  293. data/webpack/scenes/Organizations/OrganizationActions.js +5 -1
  294. data/webpack/scenes/RedHatRepositories/RedHatRepositoriesPage.js +31 -1
  295. data/webpack/scenes/RedHatRepositories/__tests__/RedHatRepositoriesPage.test.js +16 -0
  296. data/webpack/scenes/RedHatRepositories/__tests__/__snapshots__/RedHatRepositoriesPage.test.js.snap +11 -2
  297. data/webpack/scenes/RedHatRepositories/helpers.js +5 -5
  298. data/webpack/scenes/RedHatRepositories/index.js +11 -3
  299. data/webpack/scenes/Subscriptions/Manifest/CdnConfigurationTab/AirGappedTypeForm.js +81 -0
  300. data/webpack/scenes/Subscriptions/Manifest/CdnConfigurationTab/CdnConfigurationConstants.js +13 -0
  301. data/webpack/scenes/Subscriptions/Manifest/{CdnConfigurationForm.scss → CdnConfigurationTab/CdnConfigurationForm.scss} +0 -0
  302. data/webpack/scenes/Subscriptions/Manifest/CdnConfigurationTab/CdnTypeForm.js +106 -0
  303. data/webpack/scenes/Subscriptions/Manifest/CdnConfigurationTab/UpstreamServerTypeForm.js +259 -0
  304. data/webpack/scenes/Subscriptions/Manifest/CdnConfigurationTab/__tests__/AirGappedTypeForm.test.js +44 -0
  305. data/webpack/scenes/Subscriptions/Manifest/CdnConfigurationTab/__tests__/CdnTypeForm.test.js +67 -0
  306. data/webpack/scenes/Subscriptions/Manifest/{__tests__/CdnConfigurationForm.test.js → CdnConfigurationTab/__tests__/UpstreamServerTypeForm.test.js} +46 -17
  307. data/webpack/scenes/Subscriptions/Manifest/CdnConfigurationTab/index.js +97 -0
  308. data/webpack/scenes/Subscriptions/Manifest/ManageManifestModal.js +6 -1
  309. data/webpack/scenes/Subscriptions/UpstreamSubscriptions/__tests__/UpstreamSubscriptionsPage.test.js +0 -1
  310. data/webpack/scenes/Subscriptions/__tests__/SubscriptionsPage.test.js +0 -1
  311. data/webpack/scenes/Subscriptions/__tests__/__snapshots__/SubscriptionsActions.test.js.snap +3 -2
  312. data/webpack/scenes/Subscriptions/components/SubscriptionsTable/__tests__/SubscriptionsTable.test.js +4 -0
  313. data/webpack/scenes/Subscriptions/components/SubscriptionsTable/__tests__/__snapshots__/SubscriptionsTable.test.js.snap +9 -0
  314. data/webpack/scenes/Tasks/TaskActions.js +1 -1
  315. data/webpack/scenes/Tasks/__tests__/__snapshots__/TaskActions.test.js.snap +3 -2
  316. data/webpack/services/api/testHelpers.js +5 -3
  317. data/webpack/utils/helpers.js +6 -3
  318. metadata +81 -58
  319. data/app/services/katello/pulp/deb.rb +0 -55
  320. data/app/services/katello/pulp/distribution.rb +0 -7
  321. data/app/services/katello/pulp/docker_blob.rb +0 -7
  322. data/app/services/katello/pulp/docker_manifest.rb +0 -13
  323. data/app/services/katello/pulp/docker_manifest_list.rb +0 -14
  324. data/app/services/katello/pulp/docker_tag.rb +0 -14
  325. data/app/services/katello/pulp/erratum.rb +0 -129
  326. data/app/services/katello/pulp/file_unit.rb +0 -21
  327. data/app/services/katello/pulp/module_stream.rb +0 -39
  328. data/app/services/katello/pulp/package_category.rb +0 -7
  329. data/app/services/katello/pulp/package_group.rb +0 -20
  330. data/app/services/katello/pulp/pulp_content_unit.rb +0 -156
  331. data/app/services/katello/pulp/rpm.rb +0 -57
  332. data/app/services/katello/pulp/srpm.rb +0 -29
  333. data/app/services/katello/pulp/yum_metadata_file.rb +0 -30
  334. data/lib/monkeys/pulp3_13_checksumfix.rb +0 -17
  335. data/webpack/__mocks__/foremanReact/components/Pagination/PaginationHooks.js +0 -2
  336. data/webpack/__mocks__/foremanReact/components/Pagination/PaginationWrapper.js +0 -2
  337. data/webpack/scenes/Subscriptions/Manifest/CdnConfigurationForm.js +0 -185
@@ -3,9 +3,9 @@ import { isEqual } from 'lodash';
3
3
  import { renderWithRedux, patientlyWaitFor, within, fireEvent } from 'react-testing-lib-wrapper';
4
4
  import { nockInstance, assertNockRequest, mockForemanAutocomplete, mockSetting } from '../../../../../test-utils/nockWrapper';
5
5
  import { foremanApi } from '../../../../../services/api';
6
- import { HOST_ERRATA_KEY, ERRATA_SEARCH_QUERY } from '../../HostErrata/HostErrataConstants';
6
+ import { HOST_ERRATA_KEY, ERRATA_SEARCH_QUERY } from '../ErrataTab/HostErrataConstants';
7
7
  import { REX_FEATURES } from '../RemoteExecutionConstants';
8
- import { ErrataTab } from '../ErrataTab';
8
+ import { ErrataTab } from '../ErrataTab/ErrataTab.js';
9
9
  import mockErrataData from './errata.fixtures.json';
10
10
  import mockResolveErrataTask from './resolveErrata.fixtures.json';
11
11
 
@@ -81,11 +81,10 @@ let searchDelayScope;
81
81
  let autoSearchScope;
82
82
 
83
83
  beforeEach(() => {
84
- // jest.resetModules();
85
84
  const { results } = mockErrataData;
86
85
  [firstErrata, , thirdErrata] = results;
87
- searchDelayScope = mockSetting(nockInstance, 'autosearch_delay', 500);
88
- autoSearchScope = mockSetting(nockInstance, 'autosearch_while_typing', true);
86
+ searchDelayScope = mockSetting(nockInstance, 'autosearch_delay', 0);
87
+ autoSearchScope = mockSetting(nockInstance, 'autosearch_while_typing');
89
88
  });
90
89
 
91
90
  afterEach(() => {
@@ -813,7 +812,7 @@ test('apply button chooses katello agent if enabled', async (done) => {
813
812
  <ErrataTab />,
814
813
  options,
815
814
  );
816
- // Assert that the errata are now showing on the screen, but wait for them to appear.
815
+ // Assert that the errata are now showing on the screen, but wait for them to appear.
817
816
  await patientlyWaitFor(() => expect(getAllByText('Important')[0]).toBeInTheDocument());
818
817
 
819
818
  getByLabelText('Select row 0').click();
@@ -855,7 +854,7 @@ test('Can bulk apply via katello agent', async (done) => {
855
854
  <ErrataTab />,
856
855
  options,
857
856
  );
858
- // Assert that the errata are now showing on the screen, but wait for them to appear.
857
+ // Assert that the errata are now showing on the screen, but wait for them to appear.
859
858
  await patientlyWaitFor(() => expect(getAllByText('Important')[0]).toBeInTheDocument());
860
859
 
861
860
  getByLabelText('Select row 0').click();
@@ -874,7 +873,7 @@ test('Can bulk apply via katello agent', async (done) => {
874
873
 
875
874
  test('Can select all, exclude and bulk apply via katello agent', async (done) => {
876
875
  // This is the same test as above,
877
- // but using the table action bar instead of the Restart app button
876
+ // but using the table action bar instead of the Apply button
878
877
  const autocompleteScope = mockForemanAutocomplete(nockInstance, autocompleteUrl);
879
878
  const mockErrata = makeMockErrata({});
880
879
  const { results } = mockErrata;
@@ -902,12 +901,12 @@ test('Can select all, exclude and bulk apply via katello agent', async (done) =>
902
901
  <ErrataTab />,
903
902
  options,
904
903
  );
905
- // Assert that the errata are now showing on the screen, but wait for them to appear.
904
+ // Assert that the errata are now showing on the screen, but wait for them to appear.
906
905
  await patientlyWaitFor(() => expect(getAllByText('Important')[0]).toBeInTheDocument());
907
906
  const selectAllCheckbox = getByLabelText('Select all');
908
907
  selectAllCheckbox.click();
909
908
 
910
- getByLabelText('Select row 0').click(); // de select
909
+ getByLabelText('Select row 0').click(); // deselect
911
910
 
912
911
  const actionMenu = getByLabelText('bulk_actions');
913
912
  actionMenu.click();
@@ -948,7 +947,7 @@ test('Apply button chooses remote execution', async (done) => {
948
947
  <ErrataTab />,
949
948
  options,
950
949
  );
951
- // Assert that the errata are now showing on the screen, but wait for them to appear.
950
+ // Assert that the errata are now showing on the screen, but wait for them to appear.
952
951
  await patientlyWaitFor(() => expect(getAllByText('Important')[0]).toBeInTheDocument());
953
952
 
954
953
  getByLabelText('Select row 0').click();
@@ -981,9 +980,9 @@ test('Can bulk apply via remote execution', async (done) => {
981
980
  // eslint-disable-next-line camelcase
982
981
  const jobInvocationBody = ({ job_invocation: { inputs, feature, search_query } }) =>
983
982
  inputs[ERRATA_SEARCH_QUERY] === `errata_id ^ (${results[0].errata_id},${results[1].errata_id})` &&
984
- feature === REX_FEATURES.KATELLO_HOST_ERRATA_INSTALL &&
985
- // eslint-disable-next-line camelcase
986
- search_query === `name ^ (${hostName})`;
983
+ feature === REX_FEATURES.KATELLO_HOST_ERRATA_INSTALL_BY_SEARCH &&
984
+ // eslint-disable-next-line camelcase
985
+ search_query === `name ^ (${hostName})`;
987
986
 
988
987
  const resolveErrataScope = nockInstance
989
988
  .post(jobInvocations, jobInvocationBody)
@@ -993,7 +992,7 @@ test('Can bulk apply via remote execution', async (done) => {
993
992
  <ErrataTab />,
994
993
  renderOptions(),
995
994
  );
996
- // Assert that the errata are now showing on the screen, but wait for them to appear.
995
+ // Assert that the errata are now showing on the screen, but wait for them to appear.
997
996
  await patientlyWaitFor(() => expect(getAllByText('Important')[0]).toBeInTheDocument());
998
997
 
999
998
  getByLabelText('Select row 0').click();
@@ -1038,7 +1037,7 @@ test('Can select all, exclude and bulk apply via remote execution', async (done)
1038
1037
  <ErrataTab />,
1039
1038
  renderOptions(),
1040
1039
  );
1041
- // Assert that the errata are now showing on the screen, but wait for them to appear.
1040
+ // Assert that the errata are now showing on the screen, but wait for them to appear.
1042
1041
  await patientlyWaitFor(() => expect(getAllByText('Important')[0]).toBeInTheDocument());
1043
1042
  const selectAllCheckbox = getByLabelText('Select all');
1044
1043
  selectAllCheckbox.click();
@@ -1076,7 +1075,7 @@ test('Can apply errata in bulk via customized remote execution', async (done) =>
1076
1075
  getByLabelText('Select row 0').click();
1077
1076
  getByLabelText('Select row 1').click();
1078
1077
  const errata = `${results[0].errata_id},${results[1].errata_id}`;
1079
- const feature = REX_FEATURES.KATELLO_HOST_ERRATA_INSTALL;
1078
+ const feature = REX_FEATURES.KATELLO_HOST_ERRATA_INSTALL_BY_SEARCH;
1080
1079
  const actionMenu = getByLabelText('bulk_actions');
1081
1080
  actionMenu.click();
1082
1081
  const viaRexAction = queryByText('Apply via customized remote execution');
@@ -1176,7 +1175,7 @@ test('Can apply a single erratum to the host via customized remote execution', a
1176
1175
  const mockErrata = makeMockErrata({});
1177
1176
  const { results } = mockErrata;
1178
1177
  const { errata_id: errataId } = results[0];
1179
- const feature = REX_FEATURES.KATELLO_HOST_ERRATA_INSTALL;
1178
+ const feature = REX_FEATURES.KATELLO_HOST_ERRATA_INSTALL_BY_SEARCH;
1180
1179
  const scope = nockInstance
1181
1180
  .get(hostErrata)
1182
1181
  .query(defaultQuery)
@@ -0,0 +1,385 @@
1
+ import React from 'react';
2
+ import { renderWithRedux, patientlyWaitFor, fireEvent, within } from 'react-testing-lib-wrapper';
3
+ import { nockInstance, assertNockRequest, mockForemanAutocomplete, mockSetting } from '../../../../../test-utils/nockWrapper';
4
+ import katelloApi, { foremanApi } from '../../../../../services/api';
5
+ import mockPackagesData from './yumInstallablePackages.fixtures.json';
6
+ import PackageInstallModal from '../PackageInstallModal';
7
+ import { HOST_YUM_INSTALLABLE_PACKAGES_KEY, PACKAGE_SEARCH_QUERY } from '../../YumInstallablePackages/YumInstallablePackagesConstants';
8
+ import { REX_FEATURES } from '../RemoteExecutionConstants';
9
+
10
+ const contentFacetAttributes = {
11
+ id: 11,
12
+ uuid: 'e5761ea3-4117-4ecf-83d0-b694f99b389e',
13
+ content_view_default: false,
14
+ lifecycle_environment_library: false,
15
+ };
16
+
17
+ const renderOptions = (facetAttributes = contentFacetAttributes) => ({
18
+ apiNamespace: HOST_YUM_INSTALLABLE_PACKAGES_KEY,
19
+ initialState: {
20
+ API: {
21
+ HOST_DETAILS: {
22
+ response: {
23
+ id: 1,
24
+ name: 'test-host',
25
+ content_facet_attributes: { ...facetAttributes },
26
+ },
27
+ status: 'RESOLVED',
28
+ },
29
+ },
30
+ },
31
+ });
32
+
33
+ const hostYumInstallablePackages = katelloApi.getApiUrl('/packages');
34
+ const hostPackages = foremanApi.getApiUrl('/hosts/1/packages/install');
35
+ const jobInvocations = foremanApi.getApiUrl('/job_invocations');
36
+ const autocompleteUrl = '/hosts/1/packages/auto_complete_search';
37
+ const fakeTask = { id: '21c0f9e4-b27b-49aa-8774-6be66126043b' };
38
+
39
+ const defaultQuery = {
40
+ packages_restrict_not_installed: true,
41
+ packages_restrict_applicable: false,
42
+ packages_restrict_latest: true,
43
+ host_id: 1,
44
+ per_page: 20,
45
+ page: 1,
46
+ };
47
+
48
+ let firstPackages;
49
+ let secondPackages;
50
+ let searchDelayScope;
51
+ let autoSearchScope;
52
+
53
+ beforeEach(() => {
54
+ const { results } = mockPackagesData;
55
+ [firstPackages, secondPackages] = results;
56
+ searchDelayScope = mockSetting(nockInstance, 'autosearch_delay', 500);
57
+ autoSearchScope = mockSetting(nockInstance, 'autosearch_while_typing', true);
58
+ });
59
+
60
+ afterEach(() => {
61
+ assertNockRequest(searchDelayScope);
62
+ assertNockRequest(autoSearchScope);
63
+ });
64
+
65
+ test('Can call API for installable packages and show on screen on page load', async (done) => {
66
+ const autocompleteScope = mockForemanAutocomplete(nockInstance, autocompleteUrl);
67
+
68
+ const scope = nockInstance
69
+ .get(hostYumInstallablePackages)
70
+ .query(defaultQuery)
71
+ .reply(200, mockPackagesData);
72
+
73
+ const { getAllByText }
74
+ = renderWithRedux(<PackageInstallModal
75
+ isOpen
76
+ closeModal={jest.fn()}
77
+ hostId={1}
78
+ hostName="test-host"
79
+ showKatelloAgent={false}
80
+ />, renderOptions());
81
+
82
+ // Assert that the packages are now showing on the screen, but wait for them to appear.
83
+ await patientlyWaitFor(() => expect(getAllByText(firstPackages.name)[0]).toBeInTheDocument());
84
+ // Assert request was made and completed, see helper function
85
+ assertNockRequest(autocompleteScope);
86
+ assertNockRequest(scope, done); // Pass jest callback to confirm test is done
87
+ });
88
+
89
+ test('Can handle no installable packages being present', async (done) => {
90
+ const autocompleteScope = mockForemanAutocomplete(nockInstance, autocompleteUrl);
91
+
92
+ const noResults = {
93
+ total: 0,
94
+ subtotal: 0,
95
+ page: 1,
96
+ per_page: 20,
97
+ results: [],
98
+ };
99
+
100
+ const scope = nockInstance
101
+ .get(hostYumInstallablePackages)
102
+ .query(defaultQuery)
103
+ .reply(200, noResults);
104
+
105
+ const { queryByText }
106
+ = renderWithRedux(<PackageInstallModal
107
+ isOpen
108
+ closeModal={jest.fn()}
109
+ hostId={1}
110
+ hostName="test-host"
111
+ showKatelloAgent={false}
112
+ />, renderOptions());
113
+
114
+ // Assert that there are not any packages showing on the screen.
115
+ await patientlyWaitFor(() => expect(queryByText('No packages available to install')).toBeInTheDocument());
116
+ // Assert request was made and completed, see helper function
117
+ assertNockRequest(autocompleteScope);
118
+ assertNockRequest(scope, done); // Pass jest callback to confirm test is done
119
+ });
120
+
121
+ test('Does not show katello-agent option when disabled', async (done) => {
122
+ const autocompleteScope = mockForemanAutocomplete(nockInstance, autocompleteUrl);
123
+
124
+ const scope = nockInstance
125
+ .get(hostYumInstallablePackages)
126
+ .query(defaultQuery)
127
+ .reply(200, mockPackagesData);
128
+
129
+ const {
130
+ getAllByText, getByText, getByRole, queryByText,
131
+ } = renderWithRedux(<PackageInstallModal
132
+ isOpen
133
+ closeModal={jest.fn()}
134
+ hostId={1}
135
+ hostName="test-host"
136
+ showKatelloAgent={false}
137
+ />, renderOptions());
138
+
139
+ // Assert that the packages are now showing on the screen, but wait for them to appear.
140
+ await patientlyWaitFor(() => expect(getAllByText(firstPackages.name)[0]).toBeInTheDocument());
141
+ // Assert request was made and completed, see helper function
142
+ // find the first table row's checkbox
143
+ const checkbox = getByRole('checkbox', { name: 'Select row 0' });
144
+ // click the checkbox to make sure the Install dropdown will be enabled
145
+ fireEvent.click(checkbox);
146
+ const footer = getByRole('contentinfo');
147
+ // find the dropdown to the right of the Install button
148
+ // (no, the other one! The one that's in the footer.)
149
+ const dropdown = await patientlyWaitFor(() => within(footer).getByRole('button', { name: 'Select' }));
150
+ fireEvent.click(dropdown);
151
+ expect(getByText('Install via remote execution')).toBeInTheDocument();
152
+ // Assert that the katello-agent option is not present
153
+ expect(queryByText('katello-agent')).not.toBeInTheDocument();
154
+
155
+ assertNockRequest(autocompleteScope);
156
+ assertNockRequest(scope, done); // Pass jest callback to confirm test is done
157
+ });
158
+
159
+ test('Shows the katello-agent option when enabled', async (done) => {
160
+ const autocompleteScope = mockForemanAutocomplete(nockInstance, autocompleteUrl);
161
+
162
+ const scope = nockInstance
163
+ .get(hostYumInstallablePackages)
164
+ .query(defaultQuery)
165
+ .reply(200, mockPackagesData);
166
+
167
+ const {
168
+ getAllByText, getByText, getByRole,
169
+ } = renderWithRedux(<PackageInstallModal
170
+ isOpen
171
+ closeModal={jest.fn()}
172
+ hostId={1}
173
+ hostName="test-host"
174
+ showKatelloAgent
175
+ />, renderOptions());
176
+
177
+ // Assert that the packages are now showing on the screen, but wait for them to appear.
178
+ await patientlyWaitFor(() => expect(getAllByText(firstPackages.name)[0]).toBeInTheDocument());
179
+ // Assert request was made and completed, see helper function
180
+ // find the first table row's checkbox
181
+ const checkbox = getByRole('checkbox', { name: 'Select row 0' });
182
+ // click the checkbox to make sure the Install dropdown will be enabled
183
+ fireEvent.click(checkbox);
184
+ const footer = getByRole('contentinfo');
185
+ const dropdown = await patientlyWaitFor(() => within(footer).getByRole('button', { name: 'Select' }));
186
+ fireEvent.click(dropdown);
187
+ expect(getByText('Install via remote execution')).toBeInTheDocument();
188
+ expect(getByText('Install via katello-agent')).toBeInTheDocument();
189
+
190
+ assertNockRequest(autocompleteScope);
191
+ assertNockRequest(scope, done); // Pass jest callback to confirm test is done
192
+ });
193
+
194
+ test('Can install packages via katello-agent', async (done) => {
195
+ const autocompleteScope = mockForemanAutocomplete(nockInstance, autocompleteUrl);
196
+
197
+ const scope = nockInstance
198
+ .get(hostYumInstallablePackages)
199
+ .query(defaultQuery)
200
+ .reply(200, mockPackagesData);
201
+ const installScope = nockInstance
202
+ .put(hostPackages, { packages: [secondPackages.name, firstPackages.name] })
203
+ .reply(202, fakeTask);
204
+ const {
205
+ getAllByText, getByText, getByRole,
206
+ } = renderWithRedux(<PackageInstallModal
207
+ isOpen
208
+ closeModal={jest.fn()}
209
+ hostId={1}
210
+ hostName="test-host"
211
+ showKatelloAgent
212
+ />, renderOptions());
213
+
214
+ await patientlyWaitFor(() => expect(getAllByText(firstPackages.name)[0]).toBeInTheDocument());
215
+ // find and select the first two packages
216
+ const checkbox1 = getByRole('checkbox', { name: 'Select row 0' });
217
+ const checkbox2 = getByRole('checkbox', { name: 'Select row 1' });
218
+ fireEvent.click(checkbox1);
219
+ fireEvent.click(checkbox2);
220
+ // click the Install dropdown
221
+ const footer = getByRole('contentinfo');
222
+ const dropdown = await patientlyWaitFor(() => within(footer).getByRole('button', { name: 'Select' }));
223
+ fireEvent.click(dropdown);
224
+ // click the katello-agent option
225
+ const katelloAgentOption = getByText('Install via katello-agent');
226
+ fireEvent.click(katelloAgentOption);
227
+
228
+ assertNockRequest(autocompleteScope);
229
+ assertNockRequest(scope);
230
+ assertNockRequest(installScope, done);
231
+ });
232
+
233
+ test('Can install a package via remote execution', async (done) => {
234
+ const autocompleteScope = mockForemanAutocomplete(nockInstance, autocompleteUrl);
235
+ const scope = nockInstance
236
+ .get(hostYumInstallablePackages)
237
+ .query(defaultQuery)
238
+ .reply(200, mockPackagesData);
239
+ const installScope = nockInstance
240
+ .post(jobInvocations, {
241
+ job_invocation: {
242
+ inputs: {
243
+ [PACKAGE_SEARCH_QUERY]: `id ^ (${firstPackages.id},${secondPackages.id})`,
244
+ },
245
+ search_query: 'name ^ (test-host)',
246
+ feature: REX_FEATURES.KATELLO_PACKAGE_INSTALL_BY_SEARCH,
247
+ },
248
+ })
249
+ .reply(201);
250
+
251
+ const {
252
+ getAllByText, getByText, getByRole,
253
+ } = renderWithRedux(<PackageInstallModal
254
+ isOpen
255
+ closeModal={jest.fn()}
256
+ hostId={1}
257
+ hostName="test-host"
258
+ showKatelloAgent
259
+ />, renderOptions());
260
+
261
+ await patientlyWaitFor(() => expect(getAllByText(firstPackages.name)[0]).toBeInTheDocument());
262
+ // find and select the first two packages
263
+ const checkbox1 = getByRole('checkbox', { name: 'Select row 0' });
264
+ const checkbox2 = getByRole('checkbox', { name: 'Select row 1' });
265
+ fireEvent.click(checkbox1);
266
+ fireEvent.click(checkbox2);
267
+ // click the Install dropdown
268
+ const footer = getByRole('contentinfo');
269
+ const dropdown = await patientlyWaitFor(() => within(footer).getByRole('button', { name: 'Select' }));
270
+ fireEvent.click(dropdown);
271
+ const rexOption = getByText('Install via remote execution');
272
+ fireEvent.click(rexOption);
273
+
274
+ assertNockRequest(autocompleteScope);
275
+ assertNockRequest(scope);
276
+ assertNockRequest(installScope, done);
277
+ });
278
+
279
+ test('Can install a package via customized remote execution', async (done) => {
280
+ const autocompleteScope = mockForemanAutocomplete(nockInstance, autocompleteUrl);
281
+ const scope = nockInstance
282
+ .get(hostYumInstallablePackages)
283
+ .query(defaultQuery)
284
+ .reply(200, mockPackagesData);
285
+
286
+ const {
287
+ getAllByText, queryByText, getByRole,
288
+ } = renderWithRedux(<PackageInstallModal
289
+ isOpen
290
+ closeModal={jest.fn()}
291
+ hostId={1}
292
+ hostName="test-host"
293
+ />, renderOptions());
294
+
295
+ await patientlyWaitFor(() => expect(getAllByText(firstPackages.name)[0]).toBeInTheDocument());
296
+ // find and select the first two packages
297
+ const checkbox1 = getByRole('checkbox', { name: 'Select row 0' });
298
+ const checkbox2 = getByRole('checkbox', { name: 'Select row 1' });
299
+ fireEvent.click(checkbox1);
300
+ fireEvent.click(checkbox2);
301
+ // click the Install dropdown
302
+ const footer = getByRole('contentinfo');
303
+ const dropdown = await patientlyWaitFor(() => within(footer).getByRole('button', { name: 'Select' }));
304
+ fireEvent.click(dropdown);
305
+ const customizedRexOption = queryByText('Install via customized remote execution');
306
+ expect(customizedRexOption).toBeInTheDocument();
307
+ expect(customizedRexOption).toHaveAttribute(
308
+ 'href',
309
+ `/job_invocations/new?feature=${REX_FEATURES.KATELLO_PACKAGE_INSTALL}&host_ids=name%20%5E%20(test-host)&inputs%5Bpackage%5D=duck,cheetah`,
310
+ );
311
+ assertNockRequest(autocompleteScope);
312
+ assertNockRequest(scope, done);
313
+ });
314
+
315
+ test('Uses package_install_by_search_query template when in select all mode', async (done) => {
316
+ const autocompleteScope = mockForemanAutocomplete(nockInstance, autocompleteUrl);
317
+ const scope = nockInstance
318
+ .get(hostYumInstallablePackages)
319
+ .query(defaultQuery)
320
+ .reply(200, mockPackagesData);
321
+
322
+ const {
323
+ getAllByText, queryByText, getByRole,
324
+ } = renderWithRedux(<PackageInstallModal
325
+ isOpen
326
+ closeModal={jest.fn()}
327
+ hostId={1}
328
+ hostName="test-host"
329
+ />, renderOptions());
330
+
331
+ await patientlyWaitFor(() => expect(getAllByText(firstPackages.name)[0]).toBeInTheDocument());
332
+ // find and click the select all checkbox
333
+ const selectAllCheckbox = getByRole('checkbox', { name: 'Select all' });
334
+ fireEvent.click(selectAllCheckbox);
335
+ // find and deselect the first package
336
+ const checkbox1 = getByRole('checkbox', { name: 'Select row 0' });
337
+ fireEvent.click(checkbox1);
338
+ // click the Install dropdown
339
+ const footer = getByRole('contentinfo');
340
+ const dropdown = await patientlyWaitFor(() => within(footer).getByRole('button', { name: 'Select' }));
341
+ fireEvent.click(dropdown);
342
+ const customizedRexOption = queryByText('Install via customized remote execution');
343
+ expect(customizedRexOption).toBeInTheDocument();
344
+ expect(customizedRexOption).toHaveAttribute(
345
+ 'href',
346
+ `/job_invocations/new?feature=${REX_FEATURES.KATELLO_PACKAGE_INSTALL_BY_SEARCH}&host_ids=name%20%5E%20(test-host)&inputs%5BPackage%20search%20query%5D=id%20!%5E%20(32376)`,
347
+ );
348
+ assertNockRequest(autocompleteScope);
349
+ assertNockRequest(scope, done);
350
+ });
351
+
352
+ test('Disables the katello-agent option when in select all mode', async (done) => {
353
+ const autocompleteScope = mockForemanAutocomplete(nockInstance, autocompleteUrl);
354
+ const scope = nockInstance
355
+ .get(hostYumInstallablePackages)
356
+ .query(defaultQuery)
357
+ .reply(200, mockPackagesData);
358
+
359
+ const {
360
+ getAllByText, getByText, getByRole,
361
+ } = renderWithRedux(<PackageInstallModal
362
+ isOpen
363
+ closeModal={jest.fn()}
364
+ hostId={1}
365
+ hostName="test-host"
366
+ showKatelloAgent
367
+ />, renderOptions());
368
+
369
+ await patientlyWaitFor(() => expect(getAllByText(firstPackages.name)[0]).toBeInTheDocument());
370
+ // find and click the select all checkbox
371
+ const selectAllCheckbox = getByRole('checkbox', { name: 'Select all' });
372
+ fireEvent.click(selectAllCheckbox);
373
+ // find and deselect the first package
374
+ const checkbox1 = getByRole('checkbox', { name: 'Select row 0' });
375
+ fireEvent.click(checkbox1);
376
+ // click the Install dropdown
377
+ const footer = getByRole('contentinfo');
378
+ const dropdown = await patientlyWaitFor(() => within(footer).getByRole('button', { name: 'Select' }));
379
+ fireEvent.click(dropdown);
380
+ const katelloAgentOption = getByText('Install via katello-agent');
381
+ // expect the katello-agent option to be disabled
382
+ expect(katelloAgentOption).toHaveAttribute('aria-disabled', 'true');
383
+ assertNockRequest(autocompleteScope);
384
+ assertNockRequest(scope, done);
385
+ });
@@ -22,7 +22,7 @@
22
22
  "id": 676,
23
23
  "name": "acl",
24
24
  "nvra": "acl-2.2.53-1.el8.x86_64",
25
- "upgradable_version": "acl-2.5.3-1.el8.x86_64"
25
+ "upgradable_version": null
26
26
  }
27
27
  ]
28
28
  }
@@ -1,5 +1,5 @@
1
1
  import React from 'react';
2
- import { renderWithRedux, patientlyWaitFor } from 'react-testing-lib-wrapper';
2
+ import { renderWithRedux, patientlyWaitFor, fireEvent } from 'react-testing-lib-wrapper';
3
3
  import { nockInstance, assertNockRequest, mockForemanAutocomplete, mockSetting } from '../../../../../test-utils/nockWrapper';
4
4
  import { foremanApi } from '../../../../../services/api';
5
5
  import { HOST_PACKAGES_KEY } from '../../HostPackages/HostPackagesConstants';
@@ -20,6 +20,7 @@ const renderOptions = (facetAttributes = contentFacetAttributes) => ({
20
20
  HOST_DETAILS: {
21
21
  response: {
22
22
  id: 1,
23
+ name: 'test-host',
23
24
  content_facet_attributes: { ...facetAttributes },
24
25
  },
25
26
  status: 'RESOLVED',
@@ -28,8 +29,14 @@ const renderOptions = (facetAttributes = contentFacetAttributes) => ({
28
29
  },
29
30
  });
30
31
 
31
- const hostPackages = foremanApi.getApiUrl('/hosts/1/packages?include_latest_upgradable=true&per_page=20&page=1');
32
+ const hostPackages = foremanApi.getApiUrl('/hosts/1/packages');
32
33
  const autocompleteUrl = '/hosts/1/packages/auto_complete_search';
34
+ const defaultQueryWithoutSearch = {
35
+ include_latest_upgradable: true,
36
+ per_page: 20,
37
+ page: 1,
38
+ };
39
+ const defaultQuery = { ...defaultQueryWithoutSearch, search: '' };
33
40
 
34
41
  let firstPackages;
35
42
  let searchDelayScope;
@@ -38,8 +45,8 @@ let autoSearchScope;
38
45
  beforeEach(() => {
39
46
  const { results } = mockPackagesData;
40
47
  [firstPackages] = results;
41
- searchDelayScope = mockSetting(nockInstance, 'autosearch_delay', 500);
42
- autoSearchScope = mockSetting(nockInstance, 'autosearch_while_typing', true);
48
+ searchDelayScope = mockSetting(nockInstance, 'autosearch_delay', 0);
49
+ autoSearchScope = mockSetting(nockInstance, 'autosearch_while_typing');
43
50
  });
44
51
 
45
52
  afterEach(() => {
@@ -50,10 +57,9 @@ afterEach(() => {
50
57
  test('Can call API for packages and show on screen on page load', async (done) => {
51
58
  // Setup autocomplete with mockForemanAutoComplete since we aren't adding /katello
52
59
  const autocompleteScope = mockForemanAutocomplete(nockInstance, autocompleteUrl);
53
-
54
- // return tracedata results when we look for packages
55
60
  const scope = nockInstance
56
61
  .get(hostPackages)
62
+ .query(defaultQuery)
57
63
  .reply(200, mockPackagesData);
58
64
 
59
65
  const { getAllByText } = renderWithRedux(<PackagesTab />, renderOptions());
@@ -65,7 +71,7 @@ test('Can call API for packages and show on screen on page load', async (done) =
65
71
  assertNockRequest(scope, done); // Pass jest callback to confirm test is done
66
72
  });
67
73
 
68
- test('Can handle no packags being present', async (done) => {
74
+ test('Can handle no packages being present', async (done) => {
69
75
  // Setup autocomplete with mockForemanAutoComplete since we aren't adding /katello
70
76
  const autocompleteScope = mockForemanAutocomplete(nockInstance, autocompleteUrl);
71
77
 
@@ -79,6 +85,7 @@ test('Can handle no packags being present', async (done) => {
79
85
 
80
86
  const scope = nockInstance
81
87
  .get(hostPackages)
88
+ .query(defaultQuery)
82
89
  .reply(200, noResults);
83
90
 
84
91
  const { queryByText } = renderWithRedux(<PackagesTab />, renderOptions());
@@ -89,3 +96,47 @@ test('Can handle no packags being present', async (done) => {
89
96
  assertNockRequest(autocompleteScope);
90
97
  assertNockRequest(scope, done); // Pass jest callback to confirm test is done
91
98
  });
99
+
100
+ test('Can filter by package status', async (done) => {
101
+ const autocompleteScope = mockForemanAutocomplete(nockInstance, autocompleteUrl);
102
+ const scope = nockInstance
103
+ .get(hostPackages)
104
+ .query(defaultQuery)
105
+ .reply(200, mockPackagesData);
106
+
107
+ const scope2 = nockInstance
108
+ .get(hostPackages)
109
+ .query({ ...defaultQuery, status: 'upgradable' })
110
+ .reply(200, { ...mockPackagesData, results: [firstPackages] });
111
+
112
+ const {
113
+ queryByText,
114
+ getByRole,
115
+ getAllByText,
116
+ getByText,
117
+ } = renderWithRedux(<PackagesTab />, renderOptions());
118
+
119
+ // Assert that the errata are now showing on the screen, but wait for them to appear.
120
+ await patientlyWaitFor(() => expect(getAllByText(firstPackages.name)[0]).toBeInTheDocument());
121
+ // the Upgradable text in the table is just a text node, while the dropdown is a button
122
+ expect(getByText('Up-to date', { ignore: ['button', 'title'] })).toBeInTheDocument();
123
+ expect(getByText('coreutils', { ignore: ['button', 'title'] })).toBeInTheDocument();
124
+ expect(getByText('acl', { ignore: ['button', 'title'] })).toBeInTheDocument();
125
+
126
+ const statusDropdown = queryByText('Status', { ignore: 'th' });
127
+ expect(statusDropdown).toBeInTheDocument();
128
+ fireEvent.click(statusDropdown);
129
+ const upgradable = getByRole('option', { name: 'select Upgradable' });
130
+ fireEvent.click(upgradable);
131
+ await patientlyWaitFor(() => {
132
+ expect(queryByText('coreutils')).toBeInTheDocument();
133
+ expect(queryByText('acl')).not.toBeInTheDocument();
134
+ });
135
+
136
+
137
+ assertNockRequest(autocompleteScope);
138
+ assertNockRequest(scope);
139
+ assertNockRequest(searchDelayScope);
140
+ assertNockRequest(autoSearchScope);
141
+ assertNockRequest(scope2, done); // Pass jest callback to confirm test is done
142
+ });
@@ -59,8 +59,8 @@ beforeEach(() => {
59
59
  const { results } = mockRepoSetData;
60
60
  [firstRepoSet] = results;
61
61
  bookmarkScope = nockInstance.get(repositorySetBookmarks).reply(200, mockBookmarkData);
62
- searchDelayScope = mockSetting(nockInstance, 'autosearch_delay', 500);
63
- autoSearchScope = mockSetting(nockInstance, 'autosearch_while_typing', true);
62
+ searchDelayScope = mockSetting(nockInstance, 'autosearch_delay', 0);
63
+ autoSearchScope = mockSetting(nockInstance, 'autosearch_while_typing');
64
64
  });
65
65
 
66
66
  afterEach(() => {
@@ -3,8 +3,8 @@ import { renderWithRedux, waitFor, patientlyWaitFor, fireEvent, act } from 'reac
3
3
  import nock, { nockInstance, assertNockRequest, mockForemanAutocomplete, mockSetting } from '../../../../../test-utils/nockWrapper';
4
4
  import { foremanApi } from '../../../../../services/api';
5
5
  import { REX_FEATURES } from '../RemoteExecutionConstants';
6
- import { HOST_TRACES_KEY, TRACES_SEARCH_QUERY } from '../HostTracesConstants';
7
- import TracesTab from '../TracesTab';
6
+ import { HOST_TRACES_KEY, TRACES_SEARCH_QUERY } from '../TracesTab/HostTracesConstants';
7
+ import TracesTab from '../TracesTab/TracesTab.js';
8
8
  import mockTraceData from './traces.fixtures.json';
9
9
  import mockResolveTraceTask from './resolveTraces.fixtures.json';
10
10
  import emptyTraceResults from './tracerEmptyTraceResults.fixtures.json';
@@ -59,8 +59,8 @@ describe('With tracer installed', () => {
59
59
  beforeEach(() => {
60
60
  const { results } = mockTraceData;
61
61
  [firstTrace, secondTrace] = results;
62
- searchDelayScope = mockSetting(nockInstance, 'autosearch_delay', 500);
63
- autoSearchScope = mockSetting(nockInstance, 'autosearch_while_typing', true);
62
+ searchDelayScope = mockSetting(nockInstance, 'autosearch_delay', 0);
63
+ autoSearchScope = mockSetting(nockInstance, 'autosearch_while_typing');
64
64
  });
65
65
 
66
66
  afterEach(() => {