katello 4.3.0.rc1 → 4.3.0.rc2

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 (208) hide show
  1. checksums.yaml +4 -4
  2. data/app/controllers/katello/api/v2/api_controller.rb +4 -0
  3. data/app/controllers/katello/api/v2/host_errata_controller.rb +5 -0
  4. data/app/controllers/katello/api/v2/host_packages_controller.rb +2 -0
  5. data/app/controllers/katello/api/v2/host_tracer_controller.rb +4 -0
  6. data/app/controllers/katello/api/v2/repository_sets_controller.rb +2 -2
  7. data/app/controllers/katello/api/v2/root_controller.rb +10 -19
  8. data/app/controllers/katello/concerns/api/v2/bulk_extensions.rb +3 -13
  9. data/app/controllers/katello/remote_execution_controller.rb +1 -1
  10. data/app/lib/actions/katello/capsule_content/sync_capsule.rb +7 -5
  11. data/app/lib/actions/katello/repository/destroy.rb +3 -3
  12. data/app/lib/actions/pulp/repository/sync.rb +0 -2
  13. data/app/lib/actions/pulp3/abstract_async_task.rb +16 -4
  14. data/app/lib/katello/resources/cdn.rb +10 -1
  15. data/app/models/katello/concerns/host_managed_extensions.rb +7 -4
  16. data/app/models/katello/concerns/smart_proxy_extensions.rb +6 -2
  17. data/app/models/katello/content_view_version.rb +1 -6
  18. data/app/models/katello/glue/pulp/repo.rb +1 -2
  19. data/app/models/katello/host_tracer.rb +2 -0
  20. data/app/models/katello/repository.rb +2 -30
  21. data/app/models/katello/root_repository.rb +3 -43
  22. data/app/presenters/katello/host_package_presenter.rb +21 -0
  23. data/app/services/katello/bulk_items_helper.rb +35 -0
  24. data/app/services/katello/smart_proxy_helper.rb +10 -1
  25. data/app/views/foreman/job_templates/install_errata.erb +8 -6
  26. data/app/views/foreman/job_templates/resolve_traces.erb +4 -5
  27. data/app/views/foreman/job_templates/resolve_traces_-_katello_ansible_default.erb +3 -5
  28. data/app/views/foreman/smart_proxies/_content_sync.html.erb +7 -0
  29. data/app/views/katello/api/v2/capsule_content/sync_status.json.rabl +4 -0
  30. data/app/views/katello/api/v2/{organizations/cdn_configuration.rabl → cdn_configurations/show.json.rabl} +4 -0
  31. data/app/views/katello/api/v2/content_facet/show.json.rabl +8 -0
  32. data/app/views/katello/api/v2/content_view_filters/show.json.rabl +0 -1
  33. data/app/views/katello/api/v2/content_views/base.json.rabl +1 -1
  34. data/app/views/katello/api/v2/host_packages/base.json.rabl +2 -0
  35. data/app/views/katello/api/v2/organizations/show.json.rabl +1 -1
  36. data/app/views/katello/api/v2/repositories/show.json.rabl +0 -3
  37. data/config/routes/api/v2.rb +0 -10
  38. data/db/migrate/20211115215210_drop_ostree_branches.rb +13 -0
  39. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/bastion-katello-bootstrap.js +0 -2
  40. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/bastion_katello.js +0 -3
  41. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/content-views/content-views.routes.js +0 -10
  42. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/content-views/details/views/content-view-versions.html +0 -3
  43. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/content-views/versions/content-view-version-content.controller.js +0 -10
  44. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/content-views/versions/content-view-versions.module.js +0 -1
  45. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/content-views/versions/views/content-view-version.html +0 -7
  46. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/environments/content.service.js +0 -5
  47. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/environments/environments.module.js +0 -1
  48. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/environments/environments.routes.js +0 -11
  49. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/organizations/fenced-pages.service.js +1 -2
  50. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/products/details/repositories/details/repository-details-info.controller.js +2 -4
  51. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/products/details/repositories/details/repository-details-info.filter.js +0 -10
  52. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/products/details/repositories/details/views/repository-info.html +1 -1
  53. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/products/details/repositories/new/new-repository.controller.js +3 -6
  54. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/products/details/repositories/new/views/new-repository.html +4 -1
  55. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/products/details/repositories/os-versions.service.js +1 -0
  56. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/products/details/repositories/repositories.routes.js +0 -9
  57. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/products/details/repositories/views/product-repositories.html +0 -8
  58. data/engines/bastion_katello/lib/bastion_katello/engine.rb +0 -1
  59. data/lib/katello/permission_creator.rb +0 -1
  60. data/lib/katello/plugin.rb +0 -10
  61. data/lib/katello/tasks/reset.rake +2 -2
  62. data/lib/katello/version.rb +1 -1
  63. data/webpack/components/Packages/index.js +63 -0
  64. data/webpack/components/Search/Search.js +7 -1
  65. data/webpack/components/SelectAllCheckbox/index.js +2 -2
  66. data/webpack/components/Table/MainTable.scss +7 -1
  67. data/webpack/components/Table/TableHooks.js +10 -19
  68. data/webpack/components/Table/TableWrapper.js +0 -2
  69. data/webpack/components/WithOrganization/__snapshots__/withOrganization.test.js.snap +3 -3
  70. data/webpack/components/extensions/HostDetails/HostDetailsConstants.js +1 -0
  71. data/webpack/components/extensions/HostDetails/HostDetailsSelectors.js +16 -0
  72. data/webpack/components/extensions/HostDetails/HostErrata/HostErrataConstants.js +2 -0
  73. data/webpack/components/extensions/HostDetails/HostPackages/HostPackagesActions.js +11 -0
  74. data/webpack/components/extensions/HostDetails/HostPackages/HostPackagesConstants.js +2 -0
  75. data/webpack/components/extensions/HostDetails/HostPackages/HostPackagesSelectors.js +16 -0
  76. data/webpack/components/extensions/HostDetails/Tabs/ContentTab/SecondaryTabsRoutes.js +4 -0
  77. data/webpack/components/extensions/HostDetails/Tabs/ContentTab/constants.js +1 -0
  78. data/webpack/components/extensions/HostDetails/Tabs/ErrataTab.js +119 -25
  79. data/webpack/components/extensions/HostDetails/Tabs/HostTracesConstants.js +1 -0
  80. data/webpack/components/extensions/HostDetails/Tabs/PackagesTab.js +127 -0
  81. data/webpack/components/extensions/HostDetails/Tabs/PackagesTab.scss +11 -0
  82. data/webpack/components/extensions/HostDetails/Tabs/RemoteExecutionActions.js +30 -4
  83. data/webpack/components/extensions/HostDetails/Tabs/RemoteExecutionConstants.js +1 -0
  84. data/webpack/components/extensions/HostDetails/Tabs/RepositorySetsTab/RepositorySetsActions.js +73 -0
  85. data/webpack/components/extensions/HostDetails/Tabs/RepositorySetsTab/RepositorySetsConstants.js +2 -0
  86. data/webpack/components/extensions/HostDetails/Tabs/RepositorySetsTab/RepositorySetsSelectors.js +16 -0
  87. data/webpack/components/extensions/HostDetails/Tabs/RepositorySetsTab/RepositorySetsTab.js +347 -0
  88. data/webpack/components/extensions/HostDetails/Tabs/RepositorySetsTab/RepositorySetsTab.scss +7 -0
  89. data/webpack/components/extensions/HostDetails/Tabs/TracesTab.js +38 -31
  90. data/webpack/components/extensions/HostDetails/Tabs/__tests__/bookmarks.fixtures.json +12 -0
  91. data/webpack/components/extensions/HostDetails/Tabs/__tests__/contentOverrides.fixtures.json +227 -0
  92. data/webpack/components/extensions/HostDetails/Tabs/__tests__/errataTab.test.js +423 -2
  93. data/webpack/components/extensions/HostDetails/Tabs/__tests__/packages.fixtures.json +28 -0
  94. data/webpack/components/extensions/HostDetails/Tabs/__tests__/packagesTab.test.js +91 -0
  95. data/webpack/components/extensions/HostDetails/Tabs/__tests__/repositorySets.fixtures.json +120 -0
  96. data/webpack/components/extensions/HostDetails/Tabs/__tests__/repositorySetsTab.test.js +307 -0
  97. data/webpack/components/extensions/HostDetails/Tabs/__tests__/resolveErrata.fixtures.json +35 -0
  98. data/webpack/components/extensions/HostDetails/Tabs/__tests__/tracesTab.test.js +55 -9
  99. data/webpack/components/extensions/HostDetails/Tabs/customizedRexUrlHelpers.js +28 -14
  100. data/webpack/containers/Application/overrides.scss +31 -9
  101. data/webpack/global_index.js +4 -2
  102. data/webpack/redux/reducers/RedHatRepositories/enabled.fixtures.js +0 -2
  103. data/webpack/scenes/Content/ContentConfig.js +23 -7
  104. data/webpack/scenes/ContentCredentials/ContentCredentialActions.js +18 -0
  105. data/webpack/scenes/ContentCredentials/ContentCredentialConstants.js +2 -0
  106. data/webpack/scenes/ContentCredentials/ContentCredentialSelectors.js +12 -0
  107. data/webpack/scenes/ContentCredentials/__tests__/contentCredentials.fixtures.js +73 -0
  108. data/webpack/scenes/ContentViews/Copy/CopyContentViewForm.js +1 -1
  109. data/webpack/scenes/ContentViews/Create/ContentViewFormComponents.js +3 -3
  110. data/webpack/scenes/ContentViews/Create/CreateContentViewForm.js +7 -2
  111. data/webpack/scenes/ContentViews/Create/CreateContentViewForm.scss +7 -0
  112. data/webpack/scenes/ContentViews/Create/__tests__/createContentView.test.js +9 -9
  113. data/webpack/scenes/ContentViews/Delete/ContentViewDeleteWizard.js +6 -6
  114. data/webpack/scenes/ContentViews/Delete/Steps/CVDeleteEnvironmentsSelection.js +39 -37
  115. data/webpack/scenes/ContentViews/Delete/Steps/CVDeletionReview.js +35 -33
  116. data/webpack/scenes/ContentViews/Delete/__tests__/contentViewDelete.test.js +7 -5
  117. data/webpack/scenes/ContentViews/Delete/__tests__/cvVersionsData.fixtures.json +2 -6
  118. data/webpack/scenes/ContentViews/Details/ComponentContentViews/ComponentEnvironments.js +13 -14
  119. data/webpack/scenes/ContentViews/Details/ContentViewDetails.js +18 -9
  120. data/webpack/scenes/ContentViews/Details/ContentViewInfo.js +3 -2
  121. data/webpack/scenes/ContentViews/Details/Filters/Add/__tests__/cvFilterCreateResult.fixtures.json +1 -2
  122. data/webpack/scenes/ContentViews/Details/Filters/__tests__/CVRpmFilterContent.test.js +1 -1
  123. data/webpack/scenes/ContentViews/Details/Filters/__tests__/contentViewErrataByDateDetails.fixtures.json +1 -8
  124. data/webpack/scenes/ContentViews/Details/Filters/__tests__/contentViewFilterDetail.fixtures.json +1 -2
  125. data/webpack/scenes/ContentViews/Details/Filters/__tests__/contentViewFilterDetails.test.js +3 -8
  126. data/webpack/scenes/ContentViews/Details/Filters/__tests__/cvAllRepos.fixtures.json +0 -2
  127. data/webpack/scenes/ContentViews/Details/Filters/__tests__/cvErratumFilterDetails.fixtures.json +1 -2
  128. data/webpack/scenes/ContentViews/Details/Filters/__tests__/cvFilterDetailModuleAffectedRepos.fixtures.json +1 -8
  129. data/webpack/scenes/ContentViews/Details/Filters/__tests__/cvFilterDetailWithAffectedRepos.fixtures.json +1 -8
  130. data/webpack/scenes/ContentViews/Details/Filters/__tests__/cvModuleStreamFilterDetails.fixtures.json +1 -2
  131. data/webpack/scenes/ContentViews/Details/Filters/__tests__/cvPackageFilterDetail.fixtures.json +1 -3
  132. data/webpack/scenes/ContentViews/Details/Promote/ContentViewVersionPromote.js +44 -28
  133. data/webpack/scenes/ContentViews/Details/Repositories/ContentCounts.js +2 -1
  134. data/webpack/scenes/ContentViews/Details/Repositories/ContentViewRepositories.js +1 -1
  135. data/webpack/scenes/ContentViews/Details/Repositories/LastSync.js +46 -8
  136. data/webpack/scenes/ContentViews/Details/Repositories/__tests__/contentViewDetailRepos.fixtures.json +0 -2
  137. data/webpack/scenes/ContentViews/Details/Versions/ContentViewVersionContent.js +19 -3
  138. data/webpack/scenes/ContentViews/Details/Versions/ContentViewVersionEnvironments.js +2 -2
  139. data/webpack/scenes/ContentViews/Details/Versions/ContentViewVersionErrata.js +5 -3
  140. data/webpack/scenes/ContentViews/Details/Versions/ContentViewVersionErrata.scss +5 -2
  141. data/webpack/scenes/ContentViews/Details/Versions/ContentViewVersions.js +7 -4
  142. data/webpack/scenes/ContentViews/Details/Versions/Delete/RemoveSteps/CVEnvironmentSelectionForm.js +59 -53
  143. data/webpack/scenes/ContentViews/Details/Versions/Delete/RemoveSteps/CVVersionRemoveReview.js +24 -17
  144. data/webpack/scenes/ContentViews/Details/Versions/Delete/__tests__/versionsResponseData.fixtures.json +1 -4
  145. data/webpack/scenes/ContentViews/Details/Versions/VersionDetails/ContentViewVersionRepositoryCell.js +8 -3
  146. data/webpack/scenes/ContentViews/Details/Versions/VersionDetails/__tests__/ContentViewVersionComponent.fixtures.json +1 -4
  147. data/webpack/scenes/ContentViews/Details/Versions/VersionDetails/__tests__/ContentViewVersionDetails.fixtures.json +1 -2
  148. data/webpack/scenes/ContentViews/Details/Versions/VersionDetails/__tests__/ContentViewVersionDetailsCounts.fixtures.json +1 -2
  149. data/webpack/scenes/ContentViews/Details/Versions/VersionDetails/__tests__/ContentViewVersionRepositories.fixtures.json +1 -18
  150. data/webpack/scenes/ContentViews/Details/Versions/__tests__/contentViewVersions.fixtures.json +5 -5
  151. data/webpack/scenes/ContentViews/Details/Versions/__tests__/contentViewVersions.test.js +1 -0
  152. data/webpack/scenes/ContentViews/Details/Versions/__tests__/contentViewVersionsWithTask.fixtures.json +1 -3
  153. data/webpack/scenes/ContentViews/Details/contentViewInfo.scss +0 -4
  154. data/webpack/scenes/ContentViews/Publish/CVPublishForm.js +66 -53
  155. data/webpack/scenes/ContentViews/Publish/CVPublishReview.js +40 -28
  156. data/webpack/scenes/ContentViews/Publish/PublishContentViewWizard.js +3 -3
  157. data/webpack/scenes/ContentViews/Publish/__tests__/publishContentView.test.js +14 -14
  158. data/webpack/scenes/ContentViews/Publish/cvPublishForm.scss +6 -0
  159. data/webpack/scenes/ContentViews/Table/ContentViewsTable.js +53 -12
  160. data/webpack/scenes/ContentViews/Table/tableDataGenerator.js +12 -6
  161. data/webpack/scenes/ContentViews/__tests__/contentViewPage.test.js +6 -6
  162. data/webpack/scenes/ContentViews/components/ContentViewIcon.js +6 -5
  163. data/webpack/scenes/ContentViews/components/ContentViewsCounter.js +2 -2
  164. data/webpack/scenes/ContentViews/components/EnvironmentPaths/EnvironmentPaths.js +26 -27
  165. data/webpack/scenes/ContentViews/components/EnvironmentPaths/EnvironmentPaths.scss +18 -6
  166. data/webpack/scenes/ContentViews/components/WizardHeader.js +44 -0
  167. data/webpack/scenes/ContentViews/components/contentViewIcon.scss +13 -2
  168. data/webpack/scenes/Organizations/OrganizationActions.js +22 -24
  169. data/webpack/scenes/Organizations/OrganizationConstants.js +1 -3
  170. data/webpack/scenes/Organizations/OrganizationReducer.js +0 -7
  171. data/webpack/scenes/Organizations/OrganizationSelectors.js +16 -0
  172. data/webpack/scenes/Organizations/__tests__/OrganizationActions.test.js +1 -21
  173. data/webpack/scenes/Organizations/__tests__/OrganizationReducer.test.js +0 -20
  174. data/webpack/scenes/Organizations/__tests__/organizations.fixtures.js +34 -23
  175. data/webpack/scenes/Subscriptions/Manifest/ManageManifestModal.js +151 -14
  176. data/webpack/scenes/Subscriptions/Manifest/__tests__/ManageManifestModal.test.js +150 -31
  177. data/webpack/scenes/Subscriptions/Manifest/index.js +14 -3
  178. data/webpack/utils/dateTimeHelpers.js +7 -0
  179. data/webpack/utils/helpers.js +1 -1
  180. metadata +45 -43
  181. data/app/controllers/katello/api/v2/ostree_branches_controller.rb +0 -16
  182. data/app/lib/actions/pulp/repository/presenters/ostree_presenter.rb +0 -91
  183. data/app/models/katello/ostree_branch.rb +0 -12
  184. data/app/models/katello/repository_ostree_branch.rb +0 -7
  185. data/app/services/katello/pulp/ostree_branch.rb +0 -14
  186. data/app/services/katello/pulp/repository/ostree.rb +0 -48
  187. data/app/views/katello/api/v2/ostree_branches/compare.json.rabl +0 -10
  188. data/app/views/katello/api/v2/ostree_branches/index.json.rabl +0 -7
  189. data/app/views/katello/api/v2/ostree_branches/show.json.rabl +0 -5
  190. data/app/views/katello/api/v2/root/resource_list.json.rabl +0 -3
  191. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/content-views/versions/views/content-view-version-ostree-branches.html +0 -26
  192. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/environments/details/views/environment-ostree.html +0 -27
  193. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/ostree-branches/details/ostree-branch-repositories.controller.js +0 -77
  194. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/ostree-branches/details/ostree-branch.controller.js +0 -31
  195. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/ostree-branches/details/views/ostree-branch-info.html +0 -15
  196. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/ostree-branches/details/views/ostree-branch-repositories.html +0 -72
  197. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/ostree-branches/details/views/ostree-branch.html +0 -30
  198. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/ostree-branches/ostree-branch.factory.js +0 -27
  199. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/ostree-branches/ostree-branches.controller.js +0 -67
  200. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/ostree-branches/ostree-branches.module.js +0 -15
  201. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/ostree-branches/ostree-branches.routes.js +0 -50
  202. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/ostree-branches/views/ostree-branches.html +0 -40
  203. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/products/details/repositories/details/views/repository-manage-ostree-branches.html +0 -40
  204. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/products/details/repositories/ostree-upstream-sync-policy.service.js +0 -26
  205. data/webpack/components/extensions/HostDetails/Tabs/SubscriptionTab.js +0 -12
  206. data/webpack/scenes/Content/Details/ContentCounts.js +0 -42
  207. data/webpack/scenes/Subscriptions/Manifest/__tests__/SimpleContentAccess.test.js +0 -108
  208. data/webpack/scenes/Subscriptions/Manifest/__tests__/__snapshots__/ManageManifestModal.test.js.snap +0 -158
@@ -0,0 +1,227 @@
1
+ {
2
+ "total": 6,
3
+ "subtotal": 6,
4
+ "selectable": 6,
5
+ "page": 1,
6
+ "per_page": 6,
7
+ "error": null,
8
+ "search": null,
9
+ "sort": {
10
+ "by": null,
11
+ "order": null
12
+ },
13
+ "results": [
14
+ {
15
+ "enabled": true,
16
+ "product": {
17
+ "id": 301,
18
+ "name": "ParthaProduct"
19
+ },
20
+ "content": {
21
+ "id": 7587,
22
+ "name": "empty repo",
23
+ "label": "Default_Organization_ParthaProduct_empty_repo",
24
+ "vendor": "Custom",
25
+ "content_type": "yum",
26
+ "content_url": "/custom/ParthaProduct/empty_repo",
27
+ "gpg_url": null
28
+ },
29
+ "repositories": [
30
+ {
31
+ "id": 3,
32
+ "name": "empty repo",
33
+ "arch": "noarch",
34
+ "releasever": null
35
+ }
36
+ ],
37
+ "name": "empty repo",
38
+ "vendor": "Custom",
39
+ "label": "Default_Organization_ParthaProduct_empty_repo",
40
+ "id": "1636469876198",
41
+ "type": "yum",
42
+ "gpgUrl": null,
43
+ "contentUrl": "/custom/ParthaProduct/empty_repo",
44
+ "override": "default",
45
+ "overrides": [],
46
+ "enabled_content_override": null
47
+ },
48
+ {
49
+ "enabled": true,
50
+ "product": {
51
+ "id": 301,
52
+ "name": "ParthaProduct"
53
+ },
54
+ "content": {
55
+ "id": 7586,
56
+ "name": "partha multi-errata",
57
+ "label": "Default_Organization_ParthaProduct_partha_multi-errata",
58
+ "vendor": "Custom",
59
+ "content_type": "yum",
60
+ "content_url": "/custom/ParthaProduct/partha_multi-errata",
61
+ "gpg_url": null
62
+ },
63
+ "repositories": [
64
+ {
65
+ "id": 2,
66
+ "name": "partha multi-errata",
67
+ "arch": "noarch",
68
+ "releasever": null
69
+ }
70
+ ],
71
+ "name": "partha multi-errata",
72
+ "vendor": "Custom",
73
+ "label": "Default_Organization_ParthaProduct_partha_multi-errata",
74
+ "id": "1636469778922",
75
+ "type": "yum",
76
+ "gpgUrl": null,
77
+ "contentUrl": "/custom/ParthaProduct/partha_multi-errata",
78
+ "override": "0",
79
+ "overrides": [
80
+ {
81
+ "name": "enabled",
82
+ "value": false
83
+ }
84
+ ],
85
+ "enabled_content_override": false
86
+ },
87
+ {
88
+ "enabled": true,
89
+ "product": {
90
+ "id": 303,
91
+ "name": "EPEL"
92
+ },
93
+ "content": {
94
+ "id": 7589,
95
+ "name": "EPEL",
96
+ "label": "Default_Organization_EPEL_EPEL",
97
+ "vendor": "Custom",
98
+ "content_type": "yum",
99
+ "content_url": "/custom/EPEL/EPEL",
100
+ "gpg_url": null
101
+ },
102
+ "repositories": [
103
+ {
104
+ "id": 17,
105
+ "name": "EPEL",
106
+ "arch": "noarch",
107
+ "releasever": null
108
+ }
109
+ ],
110
+ "name": "EPEL",
111
+ "vendor": "Custom",
112
+ "label": "Default_Organization_EPEL_EPEL",
113
+ "id": "1636483920840",
114
+ "type": "yum",
115
+ "gpgUrl": null,
116
+ "contentUrl": "/custom/EPEL/EPEL",
117
+ "override": "0",
118
+ "overrides": [
119
+ {
120
+ "name": "enabled",
121
+ "value": false
122
+ }
123
+ ],
124
+ "enabled_content_override": false
125
+ },
126
+ {
127
+ "enabled": true,
128
+ "product": {
129
+ "id": 302,
130
+ "name": "Pull Provider"
131
+ },
132
+ "content": {
133
+ "id": 7588,
134
+ "name": "yggdrasil",
135
+ "label": "Default_Organization_Pull_Provider_yggdrasil",
136
+ "vendor": "Custom",
137
+ "content_type": "yum",
138
+ "content_url": "/custom/Pull_Provider/yggdrasil",
139
+ "gpg_url": null
140
+ },
141
+ "repositories": [],
142
+ "name": "yggdrasil",
143
+ "vendor": "Custom",
144
+ "label": "Default_Organization_Pull_Provider_yggdrasil",
145
+ "id": "1636471500857",
146
+ "type": "yum",
147
+ "gpgUrl": null,
148
+ "contentUrl": "/custom/Pull_Provider/yggdrasil",
149
+ "override": "1",
150
+ "overrides": [
151
+ {
152
+ "name": "enabled",
153
+ "value": true
154
+ }
155
+ ],
156
+ "enabled_content_override": true
157
+ },
158
+ {
159
+ "enabled": true,
160
+ "product": {
161
+ "id": 43,
162
+ "name": "Red Hat Enterprise Linux Server"
163
+ },
164
+ "content": {
165
+ "id": 1072,
166
+ "name": "Red Hat Enterprise Linux 7 Server (RPMs)",
167
+ "label": "rhel-7-server-rpms",
168
+ "vendor": "Red Hat",
169
+ "content_type": "yum",
170
+ "content_url": "/content/dist/rhel/server/7/$releasever/$basearch/os",
171
+ "gpg_url": "file:///etc/pki/rpm-gpg/RPM-GPG-KEY-redhat-release"
172
+ },
173
+ "repositories": [
174
+ {
175
+ "id": 1,
176
+ "name": "Red Hat Enterprise Linux 7 Server RPMs x86_64 7Server",
177
+ "arch": "x86_64",
178
+ "releasever": "7Server"
179
+ }
180
+ ],
181
+ "name": "Red Hat Enterprise Linux 7 Server (RPMs)",
182
+ "vendor": "Red Hat",
183
+ "label": "rhel-7-server-rpms",
184
+ "id": "2456",
185
+ "type": "yum",
186
+ "gpgUrl": "file:///etc/pki/rpm-gpg/RPM-GPG-KEY-redhat-release",
187
+ "contentUrl": "/content/dist/rhel/server/7/$releasever/$basearch/os",
188
+ "override": "default",
189
+ "overrides": [],
190
+ "enabled_content_override": null
191
+ },
192
+ {
193
+ "enabled": false,
194
+ "product": {
195
+ "id": 43,
196
+ "name": "Red Hat Enterprise Linux Server"
197
+ },
198
+ "content": {
199
+ "id": 867,
200
+ "name": "Red Hat Enterprise Linux 7 Server - Extras (RPMs)",
201
+ "label": "rhel-7-server-extras-rpms",
202
+ "vendor": "Red Hat",
203
+ "content_type": "yum",
204
+ "content_url": "/content/dist/rhel/server/7/7Server/$basearch/extras/os",
205
+ "gpg_url": "file:///etc/pki/rpm-gpg/RPM-GPG-KEY-redhat-release"
206
+ },
207
+ "repositories": [
208
+ {
209
+ "id": 16,
210
+ "name": "Red Hat Enterprise Linux 7 Server - Extras RPMs x86_64",
211
+ "arch": "x86_64",
212
+ "releasever": null
213
+ }
214
+ ],
215
+ "name": "Red Hat Enterprise Linux 7 Server - Extras (RPMs)",
216
+ "vendor": "Red Hat",
217
+ "label": "rhel-7-server-extras-rpms",
218
+ "id": "3030",
219
+ "type": "yum",
220
+ "gpgUrl": "file:///etc/pki/rpm-gpg/RPM-GPG-KEY-redhat-release",
221
+ "contentUrl": "/content/dist/rhel/server/7/7Server/$basearch/extras/os",
222
+ "override": "default",
223
+ "overrides": [],
224
+ "enabled_content_override": null
225
+ }
226
+ ]
227
+ }
@@ -1,10 +1,13 @@
1
1
  import React from 'react';
2
- import { renderWithRedux, patientlyWaitFor, fireEvent } from 'react-testing-lib-wrapper';
2
+ import { isEqual } from 'lodash';
3
+ import { renderWithRedux, patientlyWaitFor, within, fireEvent } from 'react-testing-lib-wrapper';
3
4
  import { nockInstance, assertNockRequest, mockForemanAutocomplete, mockSetting } from '../../../../../test-utils/nockWrapper';
4
5
  import { foremanApi } from '../../../../../services/api';
5
- import { HOST_ERRATA_KEY } from '../../HostErrata/HostErrataConstants';
6
+ import { HOST_ERRATA_KEY, ERRATA_SEARCH_QUERY } from '../../HostErrata/HostErrataConstants';
7
+ import { REX_FEATURES } from '../RemoteExecutionConstants';
6
8
  import { ErrataTab } from '../ErrataTab';
7
9
  import mockErrataData from './errata.fixtures.json';
10
+ import mockResolveErrataTask from './resolveErrata.fixtures.json';
8
11
 
9
12
  const contentFacetAttributes = {
10
13
  id: 11,
@@ -12,6 +15,7 @@ const contentFacetAttributes = {
12
15
  content_view_default: false,
13
16
  lifecycle_environment_library: false,
14
17
  };
18
+ const hostName = 'foo.example.com';
15
19
 
16
20
  const renderOptions = (facetAttributes = contentFacetAttributes) => ({
17
21
  apiNamespace: HOST_ERRATA_KEY,
@@ -20,6 +24,7 @@ const renderOptions = (facetAttributes = contentFacetAttributes) => ({
20
24
  HOST_DETAILS: {
21
25
  response: {
22
26
  id: 1,
27
+ name: hostName,
23
28
  content_facet_attributes: { ...facetAttributes },
24
29
  },
25
30
  status: 'RESOLVED',
@@ -67,6 +72,8 @@ const defaultQueryWithoutSearch = {
67
72
  };
68
73
  const defaultQuery = { ...defaultQueryWithoutSearch, search: '' };
69
74
  const page2Query = { ...defaultQueryWithoutSearch, page: 2 };
75
+ const jobInvocations = foremanApi.getApiUrl('/job_invocations');
76
+ const applyByKatelloAgentUrl = foremanApi.getApiUrl('/hosts/1/errata/apply');
70
77
 
71
78
  let firstErrata;
72
79
  let thirdErrata;
@@ -783,3 +790,417 @@ test('Can filter by severity', async (done) => {
783
790
  assertNockRequest(autoSearchScope);
784
791
  assertNockRequest(scope2, done); // Pass jest callback to confirm test is done
785
792
  });
793
+
794
+ test('apply button chooses katello agent if enabled', async (done) => {
795
+ const autocompleteScope = mockForemanAutocomplete(nockInstance, autocompleteUrl);
796
+ const mockErrata = makeMockErrata({});
797
+ const options = renderOptions({
798
+ ...contentFacetAttributes,
799
+ katelloAgentInstalled: true,
800
+ katelloAgentEnabled: true,
801
+ });
802
+
803
+ const scope = nockInstance
804
+ .get(hostErrata)
805
+ .query(defaultQuery)
806
+ .reply(200, mockErrata);
807
+
808
+ const resolveErrataScope = nockInstance
809
+ .put(applyByKatelloAgentUrl)
810
+ .reply(201, mockResolveErrataTask);
811
+
812
+ const { getAllByText, getByLabelText, queryByText } = renderWithRedux(
813
+ <ErrataTab />,
814
+ options,
815
+ );
816
+ // Assert that the errata are now showing on the screen, but wait for them to appear.
817
+ await patientlyWaitFor(() => expect(getAllByText('Important')[0]).toBeInTheDocument());
818
+
819
+ getByLabelText('Select row 0').click();
820
+ getByLabelText('Select row 1').click();
821
+
822
+ const viaAction = queryByText('Apply');
823
+ expect(viaAction).toBeInTheDocument();
824
+ viaAction.click();
825
+
826
+ assertNockRequest(autocompleteScope);
827
+ assertNockRequest(resolveErrataScope);
828
+ assertNockRequest(scope, done);
829
+ });
830
+
831
+ test('Can bulk apply via katello agent', async (done) => {
832
+ const autocompleteScope = mockForemanAutocomplete(nockInstance, autocompleteUrl);
833
+ const mockErrata = makeMockErrata({});
834
+ const { results } = mockErrata;
835
+ const options = renderOptions({
836
+ ...contentFacetAttributes,
837
+ katelloAgentInstalled: true,
838
+ katelloAgentEnabled: true,
839
+ });
840
+
841
+ const scope = nockInstance
842
+ .get(hostErrata)
843
+ .query(defaultQuery)
844
+ .reply(200, mockErrata);
845
+
846
+ const postBody = ({ search }) => {
847
+ const [firstResult, secondResult] = results;
848
+ return isEqual(search, `errata_id ^ (${firstResult.errata_id},${secondResult.errata_id})`);
849
+ };
850
+ const resolveErrataScope = nockInstance
851
+ .put(applyByKatelloAgentUrl, postBody)
852
+ .reply(201, mockResolveErrataTask);
853
+
854
+ const { getAllByText, getByLabelText, queryByText } = renderWithRedux(
855
+ <ErrataTab />,
856
+ options,
857
+ );
858
+ // Assert that the errata are now showing on the screen, but wait for them to appear.
859
+ await patientlyWaitFor(() => expect(getAllByText('Important')[0]).toBeInTheDocument());
860
+
861
+ getByLabelText('Select row 0').click();
862
+ getByLabelText('Select row 1').click();
863
+
864
+ const actionMenu = getByLabelText('bulk_actions');
865
+ actionMenu.click();
866
+ const viaAction = queryByText('Apply via Katello agent');
867
+ expect(viaAction).toBeInTheDocument();
868
+ viaAction.click();
869
+
870
+ assertNockRequest(autocompleteScope);
871
+ assertNockRequest(resolveErrataScope);
872
+ assertNockRequest(scope, done);
873
+ });
874
+
875
+ test('Can select all, exclude and bulk apply via katello agent', async (done) => {
876
+ // This is the same test as above,
877
+ // but using the table action bar instead of the Restart app button
878
+ const autocompleteScope = mockForemanAutocomplete(nockInstance, autocompleteUrl);
879
+ const mockErrata = makeMockErrata({});
880
+ const { results } = mockErrata;
881
+ const options = renderOptions({
882
+ ...contentFacetAttributes,
883
+ katelloAgentInstalled: true,
884
+ katelloAgentEnabled: true,
885
+ });
886
+
887
+ const scope = nockInstance
888
+ .get(hostErrata)
889
+ .query(defaultQuery)
890
+ .reply(200, mockErrata);
891
+
892
+ const postBody = ({ search }) => {
893
+ const [firstResult] = results;
894
+ return isEqual(search, `errata_id !^ (${firstResult.errata_id})`);
895
+ };
896
+
897
+ const resolveErrataScope = nockInstance
898
+ .put(applyByKatelloAgentUrl, postBody)
899
+ .reply(201, mockResolveErrataTask);
900
+
901
+ const { getAllByText, getByLabelText, queryByText } = renderWithRedux(
902
+ <ErrataTab />,
903
+ options,
904
+ );
905
+ // Assert that the errata are now showing on the screen, but wait for them to appear.
906
+ await patientlyWaitFor(() => expect(getAllByText('Important')[0]).toBeInTheDocument());
907
+ const selectAllCheckbox = getByLabelText('Select all');
908
+ selectAllCheckbox.click();
909
+
910
+ getByLabelText('Select row 0').click(); // de select
911
+
912
+ const actionMenu = getByLabelText('bulk_actions');
913
+ actionMenu.click();
914
+ const viaAction = queryByText('Apply via Katello agent');
915
+ expect(viaAction).toBeInTheDocument();
916
+ viaAction.click();
917
+
918
+ assertNockRequest(autocompleteScope);
919
+ assertNockRequest(resolveErrataScope);
920
+ assertNockRequest(scope, done);
921
+ });
922
+
923
+ test('Apply button chooses remote execution', async (done) => {
924
+ const autocompleteScope = mockForemanAutocomplete(nockInstance, autocompleteUrl);
925
+ const mockErrata = makeMockErrata({});
926
+ const options = renderOptions({
927
+ ...contentFacetAttributes,
928
+ katelloAgentInstalled: true,
929
+ katelloAgentEnabled: true,
930
+ remoteExecutionByDefault: true,
931
+ });
932
+
933
+ const scope = nockInstance
934
+ .get(hostErrata)
935
+ .query(defaultQuery)
936
+ .reply(200, mockErrata);
937
+
938
+ const scope1 = nockInstance
939
+ .get(hostErrata)
940
+ .query(defaultQueryWithoutSearch)
941
+ .reply(200, mockErrata);
942
+
943
+ const resolveErrataScope = nockInstance
944
+ .post(jobInvocations)
945
+ .reply(201, mockResolveErrataTask);
946
+
947
+ const { getAllByText, getByLabelText, queryByText } = renderWithRedux(
948
+ <ErrataTab />,
949
+ options,
950
+ );
951
+ // Assert that the errata are now showing on the screen, but wait for them to appear.
952
+ await patientlyWaitFor(() => expect(getAllByText('Important')[0]).toBeInTheDocument());
953
+
954
+ getByLabelText('Select row 0').click();
955
+ getByLabelText('Select row 1').click();
956
+
957
+ const viaAction = queryByText('Apply');
958
+ expect(viaAction).toBeInTheDocument();
959
+ viaAction.click();
960
+
961
+ assertNockRequest(autocompleteScope);
962
+ assertNockRequest(resolveErrataScope);
963
+ assertNockRequest(scope1);
964
+ assertNockRequest(scope, done);
965
+ });
966
+
967
+ test('Can bulk apply via remote execution', async (done) => {
968
+ const autocompleteScope = mockForemanAutocomplete(nockInstance, autocompleteUrl);
969
+ const mockErrata = makeMockErrata({});
970
+ const { results } = mockErrata;
971
+ const scope = nockInstance
972
+ .get(hostErrata)
973
+ .query(defaultQuery)
974
+ .reply(200, mockErrata);
975
+
976
+ const scope1 = nockInstance
977
+ .get(hostErrata)
978
+ .query(defaultQueryWithoutSearch)
979
+ .reply(200, mockErrata);
980
+
981
+ // eslint-disable-next-line camelcase
982
+ const jobInvocationBody = ({ job_invocation: { inputs, feature, search_query } }) =>
983
+ 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})`;
987
+
988
+ const resolveErrataScope = nockInstance
989
+ .post(jobInvocations, jobInvocationBody)
990
+ .reply(201, mockResolveErrataTask);
991
+
992
+ const { getAllByText, getByLabelText, queryByText } = renderWithRedux(
993
+ <ErrataTab />,
994
+ renderOptions(),
995
+ );
996
+ // Assert that the errata are now showing on the screen, but wait for them to appear.
997
+ await patientlyWaitFor(() => expect(getAllByText('Important')[0]).toBeInTheDocument());
998
+
999
+ getByLabelText('Select row 0').click();
1000
+ getByLabelText('Select row 1').click();
1001
+
1002
+ const actionMenu = getByLabelText('bulk_actions');
1003
+ actionMenu.click();
1004
+ const viaRexAction = queryByText('Apply via remote execution');
1005
+ expect(viaRexAction).toBeInTheDocument();
1006
+ viaRexAction.click();
1007
+
1008
+ assertNockRequest(autocompleteScope);
1009
+ assertNockRequest(resolveErrataScope);
1010
+ assertNockRequest(scope1);
1011
+ assertNockRequest(scope, done);
1012
+ });
1013
+
1014
+ test('Can select all, exclude and bulk apply via remote execution', async (done) => {
1015
+ // This is the same test as above,
1016
+ // but using the table action bar instead of the Restart app button
1017
+ const autocompleteScope = mockForemanAutocomplete(nockInstance, autocompleteUrl);
1018
+ const mockErrata = makeMockErrata({});
1019
+ const { results } = mockErrata;
1020
+ const scope = nockInstance
1021
+ .get(hostErrata)
1022
+ .query(defaultQuery)
1023
+ .reply(200, mockErrata);
1024
+
1025
+ const scope1 = nockInstance
1026
+ .get(hostErrata)
1027
+ .query(defaultQueryWithoutSearch)
1028
+ .reply(200, mockErrata);
1029
+
1030
+ const jobInvocationBody = ({ job_invocation: { inputs } }) =>
1031
+ inputs[ERRATA_SEARCH_QUERY] === `errata_id !^ (${results[0].errata_id})`;
1032
+
1033
+ const resolveErrataScope = nockInstance
1034
+ .post(jobInvocations, jobInvocationBody)
1035
+ .reply(201, mockResolveErrataTask);
1036
+
1037
+ const { getAllByText, getByLabelText, queryByText } = renderWithRedux(
1038
+ <ErrataTab />,
1039
+ renderOptions(),
1040
+ );
1041
+ // Assert that the errata are now showing on the screen, but wait for them to appear.
1042
+ await patientlyWaitFor(() => expect(getAllByText('Important')[0]).toBeInTheDocument());
1043
+ const selectAllCheckbox = getByLabelText('Select all');
1044
+ selectAllCheckbox.click();
1045
+
1046
+ getByLabelText('Select row 0').click(); // de select
1047
+
1048
+ const actionMenu = getByLabelText('bulk_actions');
1049
+ actionMenu.click();
1050
+ const viaRexAction = queryByText('Apply via remote execution');
1051
+ expect(viaRexAction).toBeInTheDocument();
1052
+ viaRexAction.click();
1053
+
1054
+ assertNockRequest(autocompleteScope);
1055
+ assertNockRequest(resolveErrataScope);
1056
+ assertNockRequest(scope1);
1057
+ assertNockRequest(scope, done);
1058
+ });
1059
+
1060
+ test('Can apply errata in bulk via customized remote execution', async (done) => {
1061
+ const autocompleteScope = mockForemanAutocomplete(nockInstance, autocompleteUrl);
1062
+ const mockErrata = makeMockErrata({});
1063
+ const { results } = mockErrata;
1064
+ const scope = nockInstance
1065
+ .get(hostErrata)
1066
+ .query(defaultQuery)
1067
+ .reply(200, mockErrata);
1068
+
1069
+ const { getAllByText, getByLabelText, queryByText } = renderWithRedux(
1070
+ <ErrataTab />,
1071
+ renderOptions(),
1072
+ );
1073
+
1074
+ await patientlyWaitFor(() => expect(getAllByText('Important')[0]).toBeInTheDocument());
1075
+
1076
+ getByLabelText('Select row 0').click();
1077
+ getByLabelText('Select row 1').click();
1078
+ const errata = `${results[0].errata_id},${results[1].errata_id}`;
1079
+ const feature = REX_FEATURES.KATELLO_HOST_ERRATA_INSTALL;
1080
+ const actionMenu = getByLabelText('bulk_actions');
1081
+ actionMenu.click();
1082
+ const viaRexAction = queryByText('Apply via customized remote execution');
1083
+ expect(viaRexAction).toBeInTheDocument();
1084
+ expect(viaRexAction).toHaveAttribute(
1085
+ 'href',
1086
+ `/job_invocations/new?feature=${feature}&host_ids=name%20%5E%20(${hostName})&inputs%5BErrata%20search%20query%5D=errata_id%20%5E%20(${errata})`,
1087
+ );
1088
+
1089
+ viaRexAction.click();
1090
+ assertNockRequest(autocompleteScope);
1091
+ assertNockRequest(scope, done);
1092
+ });
1093
+
1094
+ test('Can apply a single erratum to the host via katello agent', async (done) => {
1095
+ const autocompleteScope = mockForemanAutocomplete(nockInstance, autocompleteUrl);
1096
+ const mockErrata = makeMockErrata({});
1097
+ const { results } = mockErrata;
1098
+ const options = renderOptions({
1099
+ ...contentFacetAttributes,
1100
+ katelloAgentInstalled: true,
1101
+ katelloAgentEnabled: true,
1102
+ });
1103
+
1104
+ const scope = nockInstance
1105
+ .get(hostErrata)
1106
+ .query(defaultQuery)
1107
+ .reply(200, mockErrata);
1108
+
1109
+ const postBody = ({ errata_ids: errataIds }) => isEqual(errataIds, [results[0].errata_id]);
1110
+
1111
+ const resolveErrataScope = nockInstance
1112
+ .put(applyByKatelloAgentUrl, postBody)
1113
+ .reply(201, mockResolveErrataTask);
1114
+
1115
+ const { getAllByText, getByLabelText, getByText } = renderWithRedux(
1116
+ <ErrataTab />,
1117
+ options,
1118
+ );
1119
+
1120
+ await patientlyWaitFor(() => expect(getAllByText('Important')[0]).toBeInTheDocument());
1121
+ const erratumActionMenu = within(getByLabelText('Select row 0').closest('tr')).getByLabelText('Actions');
1122
+ expect(erratumActionMenu).toHaveAttribute('aria-label', 'Actions');
1123
+ erratumActionMenu.click();
1124
+
1125
+ let viaAction;
1126
+ await patientlyWaitFor(() => {
1127
+ viaAction = getByText('Apply via Katello agent');
1128
+ expect(viaAction).toBeInTheDocument();
1129
+ });
1130
+ viaAction.click();
1131
+
1132
+ assertNockRequest(autocompleteScope);
1133
+ assertNockRequest(resolveErrataScope);
1134
+ assertNockRequest(scope, done);
1135
+ });
1136
+
1137
+ test('Can apply a single erratum to the host via remote execution', async (done) => {
1138
+ const autocompleteScope = mockForemanAutocomplete(nockInstance, autocompleteUrl);
1139
+ const mockErrata = makeMockErrata({});
1140
+ const { results } = mockErrata;
1141
+ const scope = nockInstance
1142
+ .get(hostErrata)
1143
+ .query(defaultQuery)
1144
+ .reply(200, mockErrata);
1145
+
1146
+ const jobInvocationBody = ({ job_invocation: { inputs } }) =>
1147
+ inputs[ERRATA_SEARCH_QUERY] === `errata_id = ${results[0].errata_id}`;
1148
+
1149
+ const resolveErrataScope = nockInstance
1150
+ .post(jobInvocations, jobInvocationBody)
1151
+ .reply(201, mockResolveErrataTask);
1152
+
1153
+ const { getByText, getAllByText, getByLabelText } = renderWithRedux(
1154
+ <ErrataTab />,
1155
+ renderOptions(),
1156
+ );
1157
+ await patientlyWaitFor(() => expect(getAllByText('Important')[0]).toBeInTheDocument());
1158
+ const erratumActionMenu = within(getByLabelText('Select row 0').closest('tr')).getByLabelText('Actions');
1159
+ expect(erratumActionMenu).toHaveAttribute('aria-label', 'Actions');
1160
+ erratumActionMenu.click();
1161
+
1162
+ let viaRexAction;
1163
+ await patientlyWaitFor(() => {
1164
+ viaRexAction = getByText('Apply via remote execution');
1165
+ expect(viaRexAction).toBeInTheDocument();
1166
+ });
1167
+ viaRexAction.click();
1168
+
1169
+ assertNockRequest(autocompleteScope);
1170
+ assertNockRequest(resolveErrataScope);
1171
+ assertNockRequest(scope, done);
1172
+ });
1173
+
1174
+ test('Can apply a single erratum to the host via customized remote execution', async (done) => {
1175
+ const autocompleteScope = mockForemanAutocomplete(nockInstance, autocompleteUrl);
1176
+ const mockErrata = makeMockErrata({});
1177
+ const { results } = mockErrata;
1178
+ const { errata_id: errataId } = results[0];
1179
+ const feature = REX_FEATURES.KATELLO_HOST_ERRATA_INSTALL;
1180
+ const scope = nockInstance
1181
+ .get(hostErrata)
1182
+ .query(defaultQuery)
1183
+ .reply(200, mockErrata);
1184
+
1185
+ const { getByText, getAllByText, getByLabelText } = renderWithRedux(
1186
+ <ErrataTab />,
1187
+ renderOptions(),
1188
+ );
1189
+ await patientlyWaitFor(() => expect(getAllByText('Important')[0]).toBeInTheDocument());
1190
+ const erratumActionMenu = within(getByLabelText('Select row 0').closest('tr')).getByLabelText('Actions');
1191
+ expect(erratumActionMenu).toHaveAttribute('aria-label', 'Actions');
1192
+ erratumActionMenu.click();
1193
+
1194
+ let viaRexAction;
1195
+ await patientlyWaitFor(() => {
1196
+ viaRexAction = getByText('Apply via customized remote execution');
1197
+ expect(viaRexAction).toBeInTheDocument();
1198
+ });
1199
+ viaRexAction.click();
1200
+ expect(viaRexAction).toHaveAttribute(
1201
+ 'href',
1202
+ `/job_invocations/new?feature=${feature}&host_ids=name%20%5E%20(${hostName})&inputs%5BErrata%20search%20query%5D=errata_id%20=%20${errataId}`,
1203
+ );
1204
+ assertNockRequest(autocompleteScope);
1205
+ assertNockRequest(scope, done);
1206
+ });