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,10 +1,12 @@
1
1
  import React, { useCallback, useEffect, useRef, useState } from 'react';
2
2
  import { useHistory, useLocation } from 'react-router-dom';
3
3
  import { useDispatch, useSelector } from 'react-redux';
4
+ import { capitalize, upperCase, omit } from 'lodash';
4
5
  import { translate as __ } from 'foremanReact/common/I18n';
5
6
  import { STATUS } from 'foremanReact/constants';
6
7
  import {
7
8
  Button,
9
+ Checkbox,
8
10
  Drawer,
9
11
  DrawerActions,
10
12
  DrawerCloseButton,
@@ -12,6 +14,10 @@ import {
12
14
  DrawerContentBody,
13
15
  DrawerHead,
14
16
  DrawerPanelContent,
17
+ DrawerPanelBody,
18
+ Dropdown,
19
+ DropdownItem,
20
+ KebabToggle,
15
21
  Text,
16
22
  TextContent,
17
23
  TextList,
@@ -20,19 +26,22 @@ import {
20
26
  TextListVariants,
21
27
  TextVariants,
22
28
  } from '@patternfly/react-core';
23
- import { TableVariant, Tbody, Td, Th, Thead, Tr } from '@patternfly/react-table';
29
+ import { TableVariant, Tbody, Td, Th, Thead, Tr, ActionsColumn } from '@patternfly/react-table';
24
30
  import TableWrapper from '../../../components/Table/TableWrapper';
25
31
  import {
26
32
  selectAlternateContentSources,
27
33
  selectAlternateContentSourcesError,
28
34
  selectAlternateContentSourcesStatus,
29
35
  } from '../ACSSelectors';
30
- import { useTableSort } from '../../../components/Table/TableHooks';
31
- import getAlternateContentSources, { deleteACS, getACSDetails, refreshACS } from '../ACSActions';
36
+ import { useSelectionSet, useTableSort } from '../../../components/Table/TableHooks';
37
+ import getAlternateContentSources, { deleteACS, bulkDeleteACS, getACSDetails, refreshACS, bulkRefreshACS } from '../ACSActions';
32
38
  import ACSCreateWizard from '../Create/ACSCreateWizard';
33
39
  import LastSync from '../../ContentViews/Details/Repositories/LastSync';
34
40
  import ACSExpandableDetails from '../Details/ACSExpandableDetails';
35
41
  import './ACSTable.scss';
42
+ import Loading from '../../../components/Loading';
43
+ import EmptyStateMessage from '../../../components/Table/EmptyStateMessage';
44
+ import { hasPermission } from '../../ContentViews/helpers';
36
45
 
37
46
  const ACSTable = () => {
38
47
  const response = useSelector(selectAlternateContentSources);
@@ -42,28 +51,52 @@ const ACSTable = () => {
42
51
  const [searchQuery, updateSearchQuery] = useState('');
43
52
  const [isCreateWizardOpen, setIsCreateWizardOpen] = useState(false);
44
53
  const dispatch = useDispatch();
45
- const { results, ...metadata } = response;
54
+ const metadata = omit(response, ['results']);
55
+ const {
56
+ can_create: canCreate = false,
57
+ can_edit: canEdit = false,
58
+ can_delete: canDelete = false,
59
+ can_view: canView = false,
60
+ results,
61
+ } = response;
46
62
  const { pathname } = useLocation();
47
63
  const { push } = useHistory();
48
- const acsId = pathname.split('/')[3];
64
+ const [acsId, setAcsId] = useState(pathname.split('/')[2]);
49
65
  const [expandedId, setExpandedId] = useState(acsId);
50
66
  const [isExpanded, setIsExpanded] = useState(false);
51
67
  const drawerRef = useRef(null);
68
+ const [kebabOpen, setKebabOpen] = useState(false);
69
+ const [detailsKebabOpen, setDetailsKebabOpen] = useState(false);
70
+ const [deleting, setDeleting] = useState(false);
71
+ const renderActionButtons = status === STATUS.RESOLVED && !!results?.length;
72
+ const {
73
+ selectOne, isSelected, isSelectable: _isSelectable,
74
+ selectedCount, selectionSet, ...selectionSetVars
75
+ } = useSelectionSet({
76
+ results,
77
+ metadata,
78
+ });
52
79
 
53
80
  useEffect(() => {
54
81
  if (acsId) {
55
82
  dispatch(getACSDetails(acsId));
83
+ setExpandedId(acsId);
56
84
  setIsExpanded(true);
57
85
  }
58
86
  }, [dispatch, acsId]);
59
87
 
60
- const onExpand = () => {
61
- if (drawerRef.current) drawerRef.current.focus();
62
- };
88
+ const onExpand = () => drawerRef.current && drawerRef.current.focus();
63
89
 
64
90
  const onDelete = (id) => {
65
- dispatch(deleteACS(id, () =>
66
- dispatch(getAlternateContentSources())));
91
+ setDeleting(true);
92
+ dispatch(deleteACS(id, () => {
93
+ setDeleting(false);
94
+ if (id?.toString() === acsId?.toString()) {
95
+ push('/alternate_content_sources');
96
+ } else {
97
+ dispatch(getAlternateContentSources());
98
+ }
99
+ }));
67
100
  };
68
101
 
69
102
  const onRefresh = (id) => {
@@ -71,66 +104,128 @@ const ACSTable = () => {
71
104
  dispatch(getAlternateContentSources())));
72
105
  };
73
106
 
74
- const createButtonOnclick = () => {
75
- setIsCreateWizardOpen(true);
107
+ const onBulkDelete = (ids) => {
108
+ setDeleting(true);
109
+ dispatch(bulkDeleteACS({ ids }, () => {
110
+ if (acsId && ids.has(Number(acsId))) {
111
+ push('/alternate_content_sources');
112
+ } else {
113
+ dispatch(getAlternateContentSources());
114
+ }
115
+ }));
76
116
  };
77
117
 
78
- const onClick = (id) => {
79
- setExpandedId(id);
118
+ const onBulkRefresh = (ids) => {
119
+ dispatch(bulkRefreshACS({ ids }, () =>
120
+ dispatch(getAlternateContentSources())));
121
+ };
122
+
123
+ const createButtonOnclick = () => {
124
+ setIsCreateWizardOpen(true);
80
125
  };
81
126
 
82
127
  const onCloseClick = () => {
83
128
  setExpandedId(null);
84
- push('/labs/alternate_content_sources');
129
+ setAcsId(null);
130
+ window.history.replaceState(null, '', '/alternate_content_sources');
85
131
  setIsExpanded(false);
86
132
  };
87
133
 
134
+ const onClick = (id) => {
135
+ if (Number(id) === Number(expandedId)) {
136
+ onCloseClick();
137
+ } else {
138
+ setExpandedId(id);
139
+ setAcsId(id);
140
+ window.history.replaceState(null, '', `/alternate_content_sources/${id}/details`);
141
+ setIsExpanded(true);
142
+ }
143
+ };
144
+
145
+ const isSingleSelected = rowId => (Number(rowId) === Number(acsId) ||
146
+ Number(rowId) === Number(expandedId));
147
+ const customStyle = {
148
+ borderLeft: '5px solid var(--pf-global--primary-color--100)',
149
+ };
150
+
88
151
  const PanelContent = () => {
89
152
  if (!resolved) return <></>;
90
153
  const acs = results?.find(source => source?.id === Number(expandedId));
91
- const { last_refresh: lastTask } = acs ?? {};
154
+ if (!acs && isExpanded) {
155
+ setExpandedId(null);
156
+ setIsExpanded(false);
157
+ }
158
+ const { last_refresh: lastTask, permissions } = acs ?? {};
92
159
  const { last_refresh_words: lastRefreshWords, started_at: startedAt } = lastTask ?? {};
93
160
  return (
94
- <DrawerPanelContent defaultSize="50%">
161
+ <DrawerPanelContent defaultSize="35%">
95
162
  <DrawerHead>
96
163
  {results && isExpanded &&
97
- <span ref={drawerRef}>
98
- <TextContent>
99
- <Text component={TextVariants.h1}>
100
- {acs?.name}
101
- </Text>
102
- <TextList component={TextListVariants.dl}>
103
- <TextListItem component={TextListItemVariants.dt}>
104
- {__('Last refresh :')}
105
- </TextListItem>
106
- <TextListItem
107
- aria-label="name_text_value"
108
- component={TextListItemVariants.dd}
109
- >
110
- <LastSync
111
- startedAt={startedAt}
112
- lastSync={lastTask}
113
- lastSyncWords={lastRefreshWords}
114
- emptyMessage="N/A"
115
- />
116
- </TextListItem>
117
- </TextList>
118
- </TextContent>
119
- <ACSExpandableDetails />
120
- </span>}
164
+ <div ref={drawerRef}>
165
+ <Text component={TextVariants.h1} style={{ marginTop: '0px', fontWeight: 'bold' }}>
166
+ {acs?.name}
167
+ </Text>
168
+ <TextContent>
169
+ <TextList style={{ marginBottom: '0px' }} component={TextListVariants.dl}>
170
+ <TextListItem component={TextListItemVariants.dt} style={{ fontWeight: 'normal' }}>
171
+ {__('Last refresh :')}
172
+ </TextListItem>
173
+ <TextListItem
174
+ aria-label="name_text_value"
175
+ component={TextListItemVariants.dd}
176
+ >
177
+ <LastSync
178
+ startedAt={startedAt}
179
+ lastSync={lastTask}
180
+ lastSyncWords={lastRefreshWords}
181
+ emptyMessage="N/A"
182
+ />
183
+ </TextListItem>
184
+ </TextList>
185
+ </TextContent>
186
+ </div>
187
+ }
188
+ {error && <EmptyStateMessage error={error} />}
121
189
  <DrawerActions>
122
- <Button
123
- ouiaId="refresh-acs"
124
- onClick={() => onRefresh(acs?.id)}
125
- variant="secondary"
126
- isSmall
127
- aria-label="refresh_acs"
128
- >
129
- {__('Refresh source')}
130
- </Button>
190
+ {hasPermission(permissions, 'edit_alternate_content_sources') &&
191
+ <>
192
+ <Button
193
+ ouiaId="refresh-acs"
194
+ onClick={() => onRefresh(acs?.id)}
195
+ variant="secondary"
196
+ isSmall
197
+ aria-label="refresh_acs"
198
+ >
199
+ {__('Refresh source')}
200
+ </Button>
201
+ <Dropdown
202
+ style={{ paddingRight: '0px' }}
203
+ toggle={<KebabToggle aria-label="details_actions" onToggle={setDetailsKebabOpen} style={{ paddingRight: '0px' }} />}
204
+ isOpen={detailsKebabOpen}
205
+ ouiaId="acs-details-actions"
206
+ isPlain
207
+ dropdownItems={[
208
+ <DropdownItem
209
+ aria-label="details_delete"
210
+ ouiaId="details_delete"
211
+ key="details_delete"
212
+ component="button"
213
+ onClick={() => {
214
+ setDetailsKebabOpen(false);
215
+ onDelete(acs?.id);
216
+ }}
217
+ >
218
+ {__('Delete')}
219
+ </DropdownItem>]}
220
+ />
221
+ </>
222
+ }
131
223
  <DrawerCloseButton onClick={onCloseClick} />
132
224
  </DrawerActions>
133
225
  </DrawerHead>
226
+ <DrawerPanelBody>
227
+ <ACSExpandableDetails {...{ expandedId }} />
228
+ </DrawerPanelBody>
134
229
  </DrawerPanelContent>
135
230
  );
136
231
  };
@@ -138,7 +233,7 @@ const ACSTable = () => {
138
233
  const columnHeaders = [
139
234
  __('Name'),
140
235
  __('Type'),
141
- __('Last Refresh'),
236
+ __('Last refresh'),
142
237
  ];
143
238
 
144
239
  const COLUMNS_TO_SORT_PARAMS = {
@@ -164,124 +259,202 @@ const ACSTable = () => {
164
259
  [apiSortParams],
165
260
  );
166
261
 
167
- const rowDropdownItems = ({ id }) => [
168
- {
262
+ const actionsWithPermissions = (acs) => {
263
+ const { id, permissions } = acs;
264
+ const deleteAction = {
169
265
  title: __('Delete'),
170
266
  ouiaId: `remove-acs-${id}`,
171
267
  onClick: () => {
172
268
  onDelete(id);
173
269
  },
174
- },
175
- {
270
+ };
271
+ const refreshAction = {
176
272
  title: __('Refresh'),
177
- ouiaId: `remove-acs-${id}`,
273
+ ouiaId: `refresh-acs-${id}`,
178
274
  onClick: () => {
179
275
  onRefresh(id);
180
276
  },
181
- },
182
- ];
277
+ };
278
+ return [
279
+ ...(hasPermission(permissions, 'destroy_alternate_content_sources') ? [deleteAction] : []),
280
+ ...(hasPermission(permissions, 'edit_alternate_content_sources') ? [refreshAction] : []),
281
+ ];
282
+ };
283
+
284
+ const primaryActionButton = (
285
+ <Button
286
+ ouiaId="create-acs"
287
+ onClick={createButtonOnclick}
288
+ variant="primary"
289
+ aria-label="create_acs"
290
+ >
291
+ {__('Add source')}
292
+ </Button>
293
+ );
183
294
 
184
295
  const emptyContentTitle = __("You currently don't have any alternate content sources.");
185
- const emptyContentBody = __('An alternate content source can be added by using the "Add source" button above.');
296
+ const emptyContentBody = canCreate ? __('An alternate content source can be added by using the "Add source" button below.') : '';
186
297
  const emptySearchTitle = __('No matching alternate content sources found');
187
298
  const emptySearchBody = __('Try changing your search settings.');
299
+ const showPrimaryAction = canCreate;
188
300
  /* eslint-disable react/no-array-index-key */
189
-
301
+ if (deleting) {
302
+ return <Loading loadingText={__('Please wait...')} />;
303
+ }
190
304
  return (
191
- <Drawer isExpanded={isExpanded} isInline onExpand={onExpand}>
192
- <DrawerContent panelContent={<PanelContent />}>
193
- <DrawerContentBody style={{ paddingBottom: '5%' }}>
194
- <TableWrapper
195
- {...{
196
- metadata,
197
- emptyContentTitle,
198
- emptyContentBody,
199
- emptySearchTitle,
200
- emptySearchBody,
201
- searchQuery,
202
- updateSearchQuery,
203
- error,
204
- status,
205
- fetchItems,
206
- }}
207
- ouiaId="alternate-content-sources-table"
208
- variant={TableVariant.compact}
209
- additionalListeners={[activeSortColumn, activeSortDirection]}
210
- autocompleteEndpoint="/alternate_content_sources/auto_complete_search"
211
- actionButtons={
212
- <>
213
- <Button
214
- ouiaId="create-acs"
215
- onClick={createButtonOnclick}
216
- variant="primary"
217
- aria-label="create_acs"
218
- >
219
- {__('Add source')}
220
- </Button>
221
- {isCreateWizardOpen &&
222
- <ACSCreateWizard
223
- show={isCreateWizardOpen}
224
- setIsOpen={setIsCreateWizardOpen}
225
- />
226
- }
227
- </>
305
+ <div className="primary-detail-border">
306
+ <Drawer isExpanded={isExpanded} onExpand={onExpand} style={{ minHeight: '80vH' }}>
307
+ <DrawerContent panelContent={<PanelContent />} style={{ minHeight: '80vH' }}>
308
+ <DrawerContentBody>
309
+ <TableWrapper
310
+ {...{
311
+ metadata,
312
+ emptyContentTitle,
313
+ emptyContentBody,
314
+ emptySearchTitle,
315
+ emptySearchBody,
316
+ searchQuery,
317
+ updateSearchQuery,
318
+ error,
319
+ status,
320
+ fetchItems,
321
+ showPrimaryAction,
322
+ primaryActionButton,
323
+ }}
324
+ ouiaId="alternate-content-sources-table"
325
+ variant={TableVariant.compact}
326
+ additionalListeners={[activeSortColumn, activeSortDirection]}
327
+ autocompleteEndpoint="/alternate_content_sources/auto_complete_search"
328
+ {...selectionSetVars}
329
+ actionButtons={
330
+ <>
331
+ {renderActionButtons && canCreate &&
332
+ <Button
333
+ ouiaId="create-acs"
334
+ onClick={createButtonOnclick}
335
+ variant="primary"
336
+ aria-label="create_acs"
337
+ >
338
+ {__('Add source')}
339
+ </Button>}
340
+ {renderActionButtons && (canEdit || canDelete) &&
341
+ <Dropdown
342
+ toggle={<KebabToggle aria-label="bulk_actions" onToggle={setKebabOpen} />}
343
+ isOpen={kebabOpen}
344
+ ouiaId="acs-bulk-actions"
345
+ isPlain
346
+ dropdownItems={[
347
+ <DropdownItem
348
+ aria-label="bulk_refresh"
349
+ ouiaId="bulk_refresh"
350
+ key="bulk_refresh"
351
+ isDisabled={selectedCount < 1 || !canEdit}
352
+ component="button"
353
+ onClick={() => {
354
+ setKebabOpen(false);
355
+ onBulkRefresh(selectionSet);
356
+ }}
357
+ >
358
+ {__('Refresh')}
359
+ </DropdownItem>,
360
+ <DropdownItem
361
+ aria-label="bulk_delete"
362
+ ouiaId="bulk_delete"
363
+ key="bulk_delete"
364
+ isDisabled={selectedCount < 1 || !canDelete}
365
+ component="button"
366
+ onClick={() => {
367
+ setKebabOpen(false);
368
+ onBulkDelete(selectionSet);
369
+ }}
370
+ >
371
+ {__('Delete')}
372
+ </DropdownItem>,
373
+ ]}
374
+ />}
375
+ {isCreateWizardOpen &&
376
+ <ACSCreateWizard
377
+ show={isCreateWizardOpen}
378
+ setIsOpen={setIsCreateWizardOpen}
379
+ />
380
+ }
381
+ </>
228
382
  }
229
- >
230
- <Thead>
231
- <Tr>
232
- {columnHeaders.map(col => (
383
+ displaySelectAllCheckbox={renderActionButtons}
384
+ hideSearch={!canView}
385
+ >
386
+ <Thead>
387
+ <Tr>
233
388
  <Th
234
- key={col}
235
- sort={COLUMNS_TO_SORT_PARAMS[col] ? pfSortParams(col) : undefined}
236
- >
237
- {col}
238
- </Th>
239
- ))}
240
- </Tr>
241
- </Thead>
242
- <Tbody>
243
- {results?.map((acs, index) => {
244
- const {
245
- name,
246
- id,
247
- alternate_content_source_type: acsType,
248
- last_refresh: lastTask,
249
- } = acs;
250
- const {
251
- last_refresh_words: lastRefreshWords,
252
- started_at: startedAt,
253
- } = lastTask ?? {};
254
- return (
255
- <Tr key={index}>
256
- <Td onClick={() => {
257
- onClick(id);
258
- push(`/labs/alternate_content_sources/${id}/details`);
259
- }}
389
+ key="acs-checkbox"
390
+ style={{ width: 0 }}
391
+ />
392
+ {columnHeaders.map(col => (
393
+ <Th
394
+ key={col}
395
+ sort={COLUMNS_TO_SORT_PARAMS[col] ? pfSortParams(col) : undefined}
260
396
  >
261
- <Text component="a">{name}</Text>
262
- </Td>
263
- <Td>{acsType}</Td>
264
- <Td><LastSync
265
- startedAt={startedAt}
266
- lastSync={lastTask}
267
- lastSyncWords={lastRefreshWords}
268
- emptyMessage="N/A"
269
- />
270
- </Td>
271
- <Td
272
- actions={{
273
- items: rowDropdownItems(acs),
274
- }}
275
- />
276
- </Tr>
277
- );
278
- })
397
+ {col}
398
+ </Th>
399
+ ))}
400
+ </Tr>
401
+ </Thead>
402
+ <Tbody>
403
+ {results?.map((acs, index) => {
404
+ const {
405
+ name,
406
+ id,
407
+ alternate_content_source_type: acsType,
408
+ last_refresh: lastTask,
409
+ permissions,
410
+ } = acs;
411
+ const {
412
+ last_refresh_words: lastRefreshWords,
413
+ started_at: startedAt,
414
+ } = lastTask ?? {};
415
+ return (
416
+ <Tr
417
+ key={index}
418
+ style={isSingleSelected(id) && isExpanded ? customStyle : {}}
419
+ isStriped={isSingleSelected(id) && isExpanded}
420
+ >
421
+ <Td>
422
+ <Checkbox
423
+ ouiaId={`select-acs-${id}`}
424
+ id={id}
425
+ aria-label={`Select ACS ${id}`}
426
+ isChecked={isSelected(id)}
427
+ onChange={selected => selectOne(selected, id)}
428
+ />
429
+ </Td>
430
+ <Td>
431
+ <Text onClick={() => onClick(id)} component="a">{name}</Text>
432
+ </Td>
433
+ <Td>{acsType === 'rhui' ? upperCase(acsType) : capitalize(acsType)}</Td>
434
+ <Td><LastSync
435
+ startedAt={startedAt}
436
+ lastSync={lastTask}
437
+ lastSyncWords={lastRefreshWords}
438
+ emptyMessage="N/A"
439
+ />
440
+ </Td>
441
+ {(hasPermission(permissions, 'destroy_alternate_content_sources') ||
442
+ hasPermission(permissions, 'edit_alternate_content_sources')) ?
443
+ <Td isActionCell>
444
+ <ActionsColumn items={actionsWithPermissions(acs)} />
445
+ </Td> :
446
+ <Td />
447
+ }
448
+ </Tr>
449
+ );
450
+ })
279
451
  }
280
- </Tbody>
281
- </TableWrapper>
282
- </DrawerContentBody>
283
- </DrawerContent>
284
- </Drawer>
452
+ </Tbody>
453
+ </TableWrapper>
454
+ </DrawerContentBody>
455
+ </DrawerContent>
456
+ </Drawer>
457
+ </div>
285
458
  );
286
459
  /* eslint-enable react/no-array-index-key */
287
460
  };
@@ -87,5 +87,9 @@
87
87
  "label": "test_acs_yum_1",
88
88
  "description": null
89
89
  }
90
- ]
90
+ ],
91
+ "can_create": true,
92
+ "can_delete": true,
93
+ "can_edit": true,
94
+ "can_view": true
91
95
  }
@@ -16,13 +16,6 @@ let autoSearchScope;
16
16
  beforeEach(() => {
17
17
  const { results } = acsData;
18
18
  [firstAcs] = results;
19
- searchDelayScope = mockSetting(nockInstance, 'autosearch_delay', 0);
20
- autoSearchScope = mockSetting(nockInstance, 'autosearch_while_typing');
21
- });
22
-
23
- afterEach(() => {
24
- assertNockRequest(searchDelayScope);
25
- assertNockRequest(autoSearchScope);
26
19
  });
27
20
 
28
21
  test('Can call API and show ACS on page load', async (done) => {
@@ -31,6 +24,8 @@ test('Can call API and show ACS on page load', async (done) => {
31
24
  .get(acsURL)
32
25
  .query(true)
33
26
  .reply(200, acsData);
27
+ searchDelayScope = mockSetting(nockInstance, 'autosearch_delay', 0);
28
+ autoSearchScope = mockSetting(nockInstance, 'autosearch_while_typing');
34
29
 
35
30
  const { getByText, queryByText } = renderWithRedux(<ACSTable />);
36
31
 
@@ -39,28 +34,32 @@ test('Can call API and show ACS on page load', async (done) => {
39
34
  // Assert that the ACS name is now showing on the screen, but wait for it to appear.
40
35
  await patientlyWaitFor(() => expect(getByText(firstAcs.name)).toBeInTheDocument());
41
36
  assertNockRequest(autocompleteScope);
37
+ assertNockRequest(searchDelayScope);
38
+ assertNockRequest(autoSearchScope);
42
39
  assertNockRequest(scope, done);
43
40
  });
44
41
 
45
42
  test('Can handle no ACS being present', async (done) => {
46
- const autocompleteScope = mockAutocomplete(nockInstance, autocompleteUrl);
47
-
48
43
  const noResults = {
49
44
  total: 0,
50
45
  subtotal: 0,
51
46
  page: 1,
52
47
  per_page: 20,
53
48
  results: [],
49
+ can_create: true,
50
+ can_delete: true,
51
+ can_edit: true,
52
+ can_view: true,
54
53
  };
55
54
  const scope = nockInstance
56
55
  .get(acsURL)
57
56
  .query(true)
58
57
  .reply(200, noResults);
59
58
 
60
- const { queryByText } = renderWithRedux(<ACSTable />);
59
+ const { queryByLabelText, queryByText } = renderWithRedux(<ACSTable />);
61
60
 
62
61
  expect(queryByText(firstAcs.name)).toBeNull();
62
+ expect(queryByLabelText('Select all')).not.toBeInTheDocument();
63
63
  await patientlyWaitFor(() => expect(queryByText("You currently don't have any alternate content sources.")).toBeInTheDocument());
64
- assertNockRequest(autocompleteScope);
65
64
  assertNockRequest(scope, done);
66
65
  });