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
@@ -1,5 +1,6 @@
1
1
  import React from 'react';
2
- import { render, renderWithRedux } from 'react-testing-lib-wrapper';
2
+ import { renderWithRedux, patientlyWaitFor, fireEvent } from 'react-testing-lib-wrapper';
3
+
3
4
  import ErrataOverviewCard from '../ErrataOverviewCard';
4
5
 
5
6
  const baseHostDetails = {
@@ -8,6 +9,23 @@ const baseHostDetails = {
8
9
  uuid: '123',
9
10
  },
10
11
  };
12
+ const baseFacetAttributes = {
13
+ errata_status: 0, // all up to date
14
+ content_facet_attributes: {
15
+ errata_counts: {
16
+ bugfix: 0,
17
+ enhancement: 0,
18
+ security: 0,
19
+ total: 0,
20
+ applicable: {
21
+ bugfix: 0,
22
+ enhancement: 0,
23
+ security: 0,
24
+ total: 0,
25
+ },
26
+ },
27
+ },
28
+ };
11
29
  const renderOptions = {
12
30
  initialState: {
13
31
  // This is the API state that your tests depend on for their data
@@ -22,18 +40,11 @@ describe('Without errata', () => {
22
40
  test('shows zero counts when there are 0 installable errata', () => {
23
41
  const hostDetails = {
24
42
  ...baseHostDetails,
25
- errata_status: 1,
26
- content_facet_attributes: {
27
- errata_counts: {
28
- bugfix: 0,
29
- enhancement: 0,
30
- security: 0,
31
- total: 0,
32
- },
33
- },
43
+ ...baseFacetAttributes,
44
+ errata_status: 2,
34
45
  };
35
46
  /* eslint-disable max-len */
36
- const { queryByLabelText, getByLabelText } = render(<ErrataOverviewCard hostDetails={hostDetails} />);
47
+ const { queryByLabelText, getByLabelText } = renderWithRedux(<ErrataOverviewCard hostDetails={hostDetails} />, renderOptions);
37
48
  /* eslint-enable max-len */
38
49
  expect(queryByLabelText('errataChart')).not.toBeInTheDocument();
39
50
  expect(getByLabelText('0 total errata')).toBeInTheDocument();
@@ -42,18 +53,10 @@ describe('Without errata', () => {
42
53
  expect(getByLabelText('0 enhancements')).toBeInTheDocument();
43
54
  });
44
55
 
45
- test('shows empty state when there are 0 errata', () => {
56
+ test('shows happy empty state when there are 0 errata', () => {
46
57
  const hostDetails = {
47
58
  ...baseHostDetails,
48
- errata_status: 0,
49
- content_facet_attributes: {
50
- errata_counts: {
51
- bugfix: 0,
52
- enhancement: 0,
53
- security: 0,
54
- total: 0,
55
- },
56
- },
59
+ ...baseFacetAttributes,
57
60
  };
58
61
  /* eslint-disable max-len */
59
62
  const { queryByLabelText, getByText } = renderWithRedux(<ErrataOverviewCard hostDetails={hostDetails} />, renderOptions);
@@ -62,24 +65,29 @@ describe('Without errata', () => {
62
65
  expect(getByText('All errata up-to-date')).toBeInTheDocument();
63
66
  });
64
67
 
68
+ test('shows warning empty state when it has unknown errata status', () => {
69
+ const hostDetails = {
70
+ ...baseHostDetails,
71
+ ...baseFacetAttributes,
72
+ errata_status: 1,
73
+ };
74
+ const { queryByLabelText, getByText }
75
+ = renderWithRedux(<ErrataOverviewCard hostDetails={hostDetails} />, renderOptions);
76
+ expect(queryByLabelText('errataChart')).not.toBeInTheDocument();
77
+ expect(getByText('Unknown errata status')).toBeInTheDocument();
78
+ });
79
+
65
80
  test('does not show errata card when host not registered', () => {
66
81
  const hostDetails = {
67
82
  ...baseHostDetails,
68
- content_facet_attributes: {
69
- errata_counts: {
70
- bugfix: 0,
71
- enhancement: 0,
72
- security: 0,
73
- total: 0,
74
- },
75
- },
83
+ ...baseFacetAttributes,
76
84
  subscription_facet_attributes: undefined,
77
85
  };
78
86
  /* eslint-disable max-len */
79
- const { queryByLabelText, queryByText } = render(<ErrataOverviewCard hostDetails={hostDetails} />);
87
+ const { queryByLabelText, queryByText } = renderWithRedux(<ErrataOverviewCard hostDetails={hostDetails} />, renderOptions);
80
88
  /* eslint-enable max-len */
81
89
  expect(queryByLabelText('errataChart')).not.toBeInTheDocument();
82
- expect(queryByText('0 errata')).not.toBeInTheDocument();
90
+ expect(queryByText('No errata')).not.toBeInTheDocument();
83
91
  });
84
92
  });
85
93
 
@@ -87,22 +95,127 @@ describe('With errata', () => {
87
95
  test('shows links when there are errata', () => {
88
96
  const hostDetails = {
89
97
  ...baseHostDetails,
98
+ errata_status: 2,
99
+ content_facet_attributes: {
100
+ errata_counts: {
101
+ bugfix: 10,
102
+ enhancement: 20,
103
+ security: 30,
104
+ total: 60,
105
+ applicable: {
106
+ bugfix: 10,
107
+ enhancement: 20,
108
+ security: 30,
109
+ total: 60,
110
+ },
111
+ },
112
+ },
113
+ };
114
+ const { getByLabelText, container }
115
+ = renderWithRedux(<ErrataOverviewCard hostDetails={hostDetails} />, renderOptions);
116
+ expect(container.getElementsByClassName('erratachart')).toHaveLength(1);
117
+ expect(container.getElementsByClassName('erratalegend')).toHaveLength(1);
118
+
119
+ expect(getByLabelText('60 total errata')).toBeInTheDocument();
120
+ expect(getByLabelText('30 security advisories')).toBeInTheDocument();
121
+ expect(getByLabelText('20 enhancements')).toBeInTheDocument();
122
+ expect(getByLabelText('10 bug fixes')).toBeInTheDocument();
123
+ });
124
+
125
+ test('has cute little tooltips', async () => {
126
+ const hostDetails = {
127
+ ...baseHostDetails,
128
+ errata_status: 2,
90
129
  content_facet_attributes: {
91
130
  errata_counts: {
92
131
  bugfix: 10,
93
132
  enhancement: 20,
94
133
  security: 30,
95
134
  total: 60,
135
+ applicable: {
136
+ bugfix: 10,
137
+ enhancement: 20,
138
+ security: 30,
139
+ total: 60,
140
+ },
96
141
  },
97
142
  },
98
143
  };
99
- const { getByLabelText, container } = render(<ErrataOverviewCard hostDetails={hostDetails} />);
144
+ const { getByText }
145
+ = renderWithRedux(<ErrataOverviewCard hostDetails={hostDetails} />, renderOptions);
146
+ // find the Applicable toggle button, then find the svg next to it
147
+ const applicableToggle = getByText('Applicable').parentElement.parentElement;
148
+ fireEvent.mouseEnter(applicableToggle);
149
+ // expect the tooltip to be visible
150
+ await patientlyWaitFor(() => expect(getByText('Applicable errata apply to at least one package installed on the host.')).toBeInTheDocument());
151
+ });
152
+
153
+ test('can toggle between applicable and installable with toggle group', () => {
154
+ const hostDetails = {
155
+ ...baseHostDetails,
156
+ errata_status: 2,
157
+ content_facet_attributes: {
158
+ errata_counts: {
159
+ bugfix: 10,
160
+ enhancement: 20,
161
+ security: 30,
162
+ total: 60,
163
+ applicable: {
164
+ bugfix: 11,
165
+ enhancement: 21,
166
+ security: 31,
167
+ total: 61,
168
+ },
169
+ },
170
+ },
171
+ };
172
+ const { getByLabelText, container, getByText }
173
+ = renderWithRedux(<ErrataOverviewCard hostDetails={hostDetails} />, renderOptions);
100
174
  expect(container.getElementsByClassName('erratachart')).toHaveLength(1);
101
175
  expect(container.getElementsByClassName('erratalegend')).toHaveLength(1);
102
176
 
177
+ expect(getByText('Applicable').parentElement).toHaveAttribute('aria-pressed', 'true');
178
+
179
+ expect(getByLabelText('61 total errata')).toBeInTheDocument();
180
+ expect(getByLabelText('31 security advisories')).toBeInTheDocument();
181
+ expect(getByLabelText('21 enhancements')).toBeInTheDocument();
182
+ expect(getByLabelText('11 bug fixes')).toBeInTheDocument();
183
+
184
+ fireEvent.click(getByText('Installable'));
185
+
103
186
  expect(getByLabelText('60 total errata')).toBeInTheDocument();
104
187
  expect(getByLabelText('30 security advisories')).toBeInTheDocument();
105
188
  expect(getByLabelText('20 enhancements')).toBeInTheDocument();
106
189
  expect(getByLabelText('10 bug fixes')).toBeInTheDocument();
107
190
  });
191
+ test('applicable view links to show=applicable; installable view links to show=installable', () => {
192
+ const hostDetails = {
193
+ ...baseHostDetails,
194
+ errata_status: 2,
195
+ content_facet_attributes: {
196
+ errata_counts: {
197
+ bugfix: 10,
198
+ enhancement: 20,
199
+ security: 30,
200
+ total: 60,
201
+ applicable: {
202
+ bugfix: 11,
203
+ enhancement: 21,
204
+ security: 31,
205
+ total: 61,
206
+ },
207
+ },
208
+ },
209
+ };
210
+ const { getByText, getByLabelText }
211
+ = renderWithRedux(<ErrataOverviewCard hostDetails={hostDetails} />, renderOptions);
212
+ expect(getByText('Applicable').parentElement).toHaveAttribute('aria-pressed', 'true');
213
+ expect(getByText('Installable').parentElement).toHaveAttribute('aria-pressed', 'false');
214
+
215
+ expect(getByLabelText('61 total errata').closest('a')).toHaveAttribute('href', '#/Content/errata?show=applicable');
216
+ fireEvent.click(getByText('Installable'));
217
+ expect(getByText('Applicable').parentElement).toHaveAttribute('aria-pressed', 'false');
218
+ expect(getByText('Installable').parentElement).toHaveAttribute('aria-pressed', 'true');
219
+ expect(getByLabelText('30 security advisories').closest('a')).toHaveAttribute('href', '#/Content/errata?type=security&show=installable');
220
+ });
108
221
  });
@@ -25,7 +25,9 @@ export const RegisteredBy = ({ user, activationKeys }) => {
25
25
  return (
26
26
  <>
27
27
  <List isPlain>
28
- <Text component={TextVariants.h4}>{activationKeys.length > 1 ? __('Activation keys') : __('Activation key')}</Text>
28
+ <Text component={TextVariants.h4} ouiaId="activation-key-text">
29
+ {activationKeys.length > 1 ? __('Activation keys') : __('Activation key')}
30
+ </Text>
29
31
  {activationKeys.map(key => (
30
32
  <ListItem key={key.id}>
31
33
  <a href={urlBuilder(`activation_keys/${key.id}`, '')}>{key.name}</a>
@@ -1,10 +1,11 @@
1
1
  import { translate as __ } from 'foremanReact/common/I18n';
2
2
  import { hideRepoSetsTab } from '../RepositorySetsTab/RepositorySetsTab';
3
+ import { hideModuleStreamsTab } from '../ModuleStreamsTab/ModuleStreamsTab';
3
4
 
4
5
  const SECONDARY_TABS = [
5
6
  { key: 'packages', title: __('Packages') },
6
7
  { key: 'errata', title: __('Errata') },
7
- { key: 'module-streams', title: __('Module streams') },
8
+ { key: 'module-streams', hideTab: hideModuleStreamsTab, title: __('Module streams') },
8
9
  { key: 'Repository sets', hideTab: hideRepoSetsTab, title: __('Repository sets') },
9
10
  ];
10
11
 
@@ -16,6 +16,7 @@ const ContentTab = ({ location: { pathname } }) => {
16
16
  return (
17
17
  <>
18
18
  <Tabs
19
+ ouiaId="host-content-tabs"
19
20
  className="margin-0-24"
20
21
  onSelect={(evt, subTab) => hashHistory.push(subTab)}
21
22
  isSecondary
@@ -1,8 +1,9 @@
1
- import React, { useCallback, useState } from 'react';
1
+ import React, { useCallback, useState, useMemo } from 'react';
2
+ import useDeepCompareEffect from 'use-deep-compare-effect';
2
3
  import { useSelector, useDispatch } from 'react-redux';
3
4
  import {
4
5
  Split, SplitItem, ActionList, ActionListItem, Dropdown,
5
- DropdownItem, KebabToggle, Skeleton, Tooltip, ToggleGroup, ToggleGroupItem,
6
+ DropdownItem, KebabToggle, Skeleton, Tooltip, ToggleGroup,
6
7
  DropdownToggle, DropdownToggleAction,
7
8
  } from '@patternfly/react-core';
8
9
  import { TimesIcon, CheckIcon } from '@patternfly/react-icons';
@@ -16,6 +17,7 @@ import {
16
17
  Td,
17
18
  ExpandableRowContent,
18
19
  } from '@patternfly/react-table';
20
+ import { isEqual } from 'lodash';
19
21
  import { translate as __ } from 'foremanReact/common/I18n';
20
22
  import { selectAPIResponse } from 'foremanReact/redux/API/APISelectors';
21
23
  import IsoDate from 'foremanReact/components/common/dates/IsoDate';
@@ -24,7 +26,7 @@ import { propsToCamelCase } from 'foremanReact/common/helpers';
24
26
  import SelectableDropdown from '../../../../SelectableDropdown';
25
27
  import { useSet, useBulkSelect, useUrlParams, useTableSort } from '../../../../../components/Table/TableHooks';
26
28
  import TableWrapper from '../../../../../components/Table/TableWrapper';
27
- import { ErrataType, ErrataSeverity } from '../../../../../components/Errata';
29
+ import { ErrataType, ErrataSeverity, ErrataToggleGroupItem } from '../../../../../components/Errata';
28
30
  import { getInstallableErrata, regenerateApplicability, applyViaKatelloAgent } from './HostErrataActions';
29
31
  import ErratumExpansionDetail from './ErratumExpansionDetail';
30
32
  import ErratumExpansionContents from './ErratumExpansionContents';
@@ -33,7 +35,7 @@ import { HOST_ERRATA_KEY, ERRATA_TYPES, ERRATA_SEVERITIES, TYPES_TO_PARAM, SEVER
33
35
  import { installErrata } from '../RemoteExecutionActions';
34
36
  import { errataInstallUrl } from '../customizedRexUrlHelpers';
35
37
  import './ErrataTab.scss';
36
- import hostIdNotReady from '../../HostDetailsActions';
38
+ import hostIdNotReady, { getHostDetails } from '../../HostDetailsActions';
37
39
  import { defaultRemoteActionMethod,
38
40
  hasRequiredPermissions as can,
39
41
  missingRequiredPermissions as cannot,
@@ -41,6 +43,7 @@ import { defaultRemoteActionMethod,
41
43
  userPermissionsFromHostDetails } from '../../hostDetailsHelpers';
42
44
  import SortableColumnHeaders from '../../../../Table/components/SortableColumnHeaders';
43
45
  import { useRexJobPolling } from '../RemoteExecutionHooks';
46
+ import { errataStatusContemplation, friendlyErrataStatus } from '../../../../Errata/errataHelpers';
44
47
 
45
48
  const recalculateApplicability = ['edit_hosts'];
46
49
  const invokeRexJobs = ['create_job_invocations'];
@@ -54,6 +57,7 @@ export const ErrataTab = () => {
54
57
  name: hostname,
55
58
  content_facet_attributes: contentFacetAttributes,
56
59
  errata_status: errataStatus,
60
+ errata_status_label: errataStatusLabel,
57
61
  } = hostDetails;
58
62
  const userPermissions = userPermissionsFromHostDetails({ hostDetails });
59
63
  const showRecalculate =
@@ -63,8 +67,8 @@ export const ErrataTab = () => {
63
67
  );
64
68
  const contentFacet = propsToCamelCase(contentFacetAttributes ?? {});
65
69
  const dispatch = useDispatch();
66
- const toggleGroupStates = ['all', 'installable'];
67
- const [ALL, INSTALLABLE] = toggleGroupStates;
70
+ const toggleGroupStates = ['applicable', 'installable'];
71
+ const [APPLICABLE, INSTALLABLE] = toggleGroupStates;
68
72
  const ERRATA_TYPE = __('Type');
69
73
  const ERRATA_SEVERITY = __('Severity');
70
74
  const [isBulkActionOpen, setIsBulkActionOpen] = useState(false);
@@ -82,19 +86,40 @@ export const ErrataTab = () => {
82
86
  = useState(PARAM_TO_FRIENDLY_NAME[initialType] ?? ERRATA_TYPE);
83
87
  const [errataSeveritySelected, setErrataSeveritySelected]
84
88
  = useState(PARAM_TO_FRIENDLY_NAME[initialSeverity] ?? ERRATA_SEVERITY);
85
- const activeFilters = [errataTypeSelected, errataSeveritySelected];
86
- const defaultFilters = [ERRATA_TYPE, ERRATA_SEVERITY];
89
+ const activeFilters = useMemo(() =>
90
+ [errataTypeSelected, errataSeveritySelected], [errataTypeSelected, errataSeveritySelected]);
91
+ const defaultFilters = useMemo(() =>
92
+ [ERRATA_TYPE, ERRATA_SEVERITY], [ERRATA_SEVERITY, ERRATA_TYPE]);
87
93
 
88
94
  const [isActionOpen, setIsActionOpen] = useState(false);
89
95
  const onActionToggle = () => {
90
96
  setIsActionOpen(prev => !prev);
91
97
  };
92
98
 
93
- const allUpToDate = errataStatus === 0;
94
- const emptyContentTitle = allUpToDate ? __('All errata up-to-date') : __('This host has errata that are applicable, but not installable.');
95
- const emptyContentBody = allUpToDate ? __('No action is needed because there are no applicable errata for this host.') : __("You may want to check the host's content view and lifecycle environment.");
99
+ const { allUpToDate, neededErrata } = errataStatusContemplation(errataStatus);
96
100
  const emptySearchTitle = __('No matching errata found');
97
101
  const emptySearchBody = __('Try changing your search settings.');
102
+
103
+ let emptyContentTitle;
104
+ let emptyContentBody;
105
+ switch (friendlyErrataStatus(errataStatus)) {
106
+ case 'All up to date':
107
+ emptyContentTitle = __('All up to date');
108
+ emptyContentBody = __('No action is needed because there are no applicable errata for this host.');
109
+ break;
110
+ case 'Needed':
111
+ emptyContentTitle = __('This host has errata that are applicable, but not installable.');
112
+ emptyContentBody = __("You may want to check the host's content view and lifecycle environment.");
113
+ break;
114
+ case 'Unknown':
115
+ emptyContentTitle = __('Unknown errata status');
116
+ emptyContentBody = errataStatusLabel;
117
+ break;
118
+ default:
119
+ emptyContentTitle = emptySearchTitle;
120
+ emptyContentBody = emptySearchBody;
121
+ }
122
+
98
123
  const errorSearchTitle = __('Problem searching errata');
99
124
  const columnHeaders = [
100
125
  __('Errata'),
@@ -144,13 +169,13 @@ export const ErrataTab = () => {
144
169
  return getInstallableErrata(
145
170
  hostId,
146
171
  {
147
- include_applicable: toggleGroupState === ALL,
172
+ include_applicable: toggleGroupState === APPLICABLE,
148
173
  ...apiSortParams,
149
174
  ...modifiedParams,
150
175
  },
151
176
  );
152
177
  },
153
- [hostId, toggleGroupState, ALL, ERRATA_SEVERITY, ERRATA_TYPE,
178
+ [hostId, toggleGroupState, APPLICABLE, ERRATA_SEVERITY, ERRATA_TYPE,
154
179
  errataTypeSelected, errataSeveritySelected, apiSortParams],
155
180
  );
156
181
 
@@ -177,7 +202,7 @@ export const ErrataTab = () => {
177
202
  const {
178
203
  triggerJobStart: triggerBulkApply, lastCompletedJob: lastCompletedBulkApply,
179
204
  isPolling: isBulkApplyInProgress,
180
- } = useRexJobPolling(installErrataAction);
205
+ } = useRexJobPolling(installErrataAction, getHostDetails({ hostname }));
181
206
 
182
207
  const installErratumAction = id => installErrata({
183
208
  hostname,
@@ -200,6 +225,24 @@ export const ErrataTab = () => {
200
225
  variant: 'checkbox',
201
226
  }), [isSelectable, isSelected, selectOne]);
202
227
 
228
+ // If the API results for total errata don't match hostDetails.contentFacet's
229
+ // stored errata counts, this probably means the stored errata counts have been
230
+ // updated and we should trigger a refresh of hostDetails.
231
+ useDeepCompareEffect(() => {
232
+ if (!metadata || !contentFacet) return;
233
+ const resultCount = metadata?.total;
234
+ // eslint-disable-next-line no-restricted-globals
235
+ if (isNaN(resultCount)) return;
236
+ const { search } = metadata;
237
+ const isFiltering = !isEqual(activeFilters, defaultFilters);
238
+ const errataTotal = contentFacet?.errataCounts?.total;
239
+ const shouldTrigger = (errataTotal !== resultCount && !isFiltering && !search);
240
+ if (shouldTrigger) {
241
+ dispatch(getHostDetails({ hostname })); // this will update the errata overview chart
242
+ }
243
+ }, [activeFilters, defaultFilters, metadata,
244
+ contentFacet.errataCounts?.total, contentFacet, dispatch, hostname]);
245
+
203
246
  if (!hostId) return <Skeleton />;
204
247
 
205
248
  const applyErratumViaRemoteExecution = id => triggerApply(id);
@@ -254,6 +297,7 @@ export const ErrataTab = () => {
254
297
  const dropdownKebabItems = [
255
298
  <DropdownItem
256
299
  aria-label="bulk_add"
300
+ ouiaId="bulk_add"
257
301
  key="bulk_add"
258
302
  component="button"
259
303
  onClick={recalculateErrata}
@@ -265,6 +309,7 @@ export const ErrataTab = () => {
265
309
  const dropdownItems = [
266
310
  <DropdownItem
267
311
  aria-label="apply_via_remote_execution"
312
+ ouiaId="apply_via_remote_execution"
268
313
  key="apply_via_remote_execution"
269
314
  component="button"
270
315
  onClick={applyViaRemoteExecution}
@@ -274,6 +319,7 @@ export const ErrataTab = () => {
274
319
  </DropdownItem>,
275
320
  <DropdownItem
276
321
  aria-label="apply_via_customized_remote_execution"
322
+ ouiaId="apply_via_customized_remote_execution"
277
323
  key="apply_via_customized_remote_execution"
278
324
  component="a"
279
325
  href={bulkCustomizedRexUrl()}
@@ -287,6 +333,7 @@ export const ErrataTab = () => {
287
333
  dropdownItems.unshift((
288
334
  <DropdownItem
289
335
  aria-label="apply_via_katello_agent"
336
+ ouiaId="apply_via_katello_agent"
290
337
  key="apply_via_katello_agent"
291
338
  component="button"
292
339
  onClick={applyByKatelloAgent}
@@ -318,9 +365,11 @@ export const ErrataTab = () => {
318
365
  <ActionListItem>
319
366
  <Dropdown
320
367
  aria-label="errata_dropdown"
368
+ ouiaId="errata_dropdown"
321
369
  toggle={
322
370
  <DropdownToggle
323
371
  aria-label="expand_errata_toggle"
372
+ ouiaId="expand_errata_toggle"
324
373
  splitButtonItems={[
325
374
  <DropdownToggleAction key="action" aria-label="bulk_actions" onClick={apply}>
326
375
  {__('Apply')}
@@ -339,6 +388,7 @@ export const ErrataTab = () => {
339
388
  {showRecalculate &&
340
389
  <ActionListItem>
341
390
  <Dropdown
391
+ ouiaId="bulk-actions-dropdown"
342
392
  toggle={<KebabToggle aria-label="bulk_actions_kebab" onToggle={toggleBulkAction} />}
343
393
  isOpen={isBulkActionOpen}
344
394
  isPlain
@@ -382,17 +432,19 @@ export const ErrataTab = () => {
382
432
  {hostIsNonLibrary &&
383
433
  <SplitItem>
384
434
  <ToggleGroup aria-label="Installable Errata">
385
- <ToggleGroupItem
386
- text={__('All')}
387
- buttonId="allToggle"
388
- aria-label="Show All"
389
- isSelected={toggleGroupState === ALL}
390
- onChange={() => setToggleGroupState(ALL)}
435
+ <ErrataToggleGroupItem
436
+ text={__('Applicable')}
437
+ tooltipText={__('Applicable errata apply to at least one package installed on the host.')}
438
+ buttonId="applicableToggle"
439
+ aria-label="Show applicable errata"
440
+ isSelected={toggleGroupState === APPLICABLE}
441
+ onChange={() => setToggleGroupState(APPLICABLE)}
391
442
  />
392
- <ToggleGroupItem
443
+ <ErrataToggleGroupItem
393
444
  text={__('Installable')}
445
+ tooltipText={__('Installable errata are applicable errata that are available in the host\'s content view and lifecycle environment.')}
394
446
  buttonId="installableToggle"
395
- aria-label="Show Installable"
447
+ aria-label="Show installable errata"
396
448
  isSelected={toggleGroupState === INSTALLABLE}
397
449
  onChange={() => setToggleGroupState(INSTALLABLE)}
398
450
  />
@@ -443,10 +495,10 @@ export const ErrataTab = () => {
443
495
  displaySelectAllCheckbox={showActions}
444
496
  requestKey={HOST_ERRATA_KEY}
445
497
  alwaysShowActionButtons={false}
446
- alwaysShowToggleGroup={hostIsNonLibrary}
498
+ alwaysShowToggleGroup={hostIsNonLibrary && neededErrata}
447
499
  >
448
500
  <Thead>
449
- <Tr>
501
+ <Tr ouiaId="row-header">
450
502
  <Th key="expand-carat" />
451
503
  <Th key="select-all" />
452
504
  <SortableColumnHeaders
@@ -501,7 +553,7 @@ export const ErrataTab = () => {
501
553
 
502
554
  return (
503
555
  <Tbody isExpanded={isExpanded} key={`${id}_${createdAt}`}>
504
- <Tr>
556
+ <Tr ouiaId={`row-${rowIndex}`}>
505
557
  <Td
506
558
  expand={{
507
559
  rowIndex,
@@ -547,7 +599,7 @@ export const ErrataTab = () => {
547
599
  />
548
600
  ) : null}
549
601
  </Tr>
550
- <Tr key="child_row" isExpanded={isExpanded}>
602
+ <Tr key="child_row" ouiaId="row-child" isExpanded={isExpanded}>
551
603
  {isExpanded && (
552
604
  <>
553
605
  <Td colSpan={3}>