katello 3.16.2 → 3.17.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 (381) hide show
  1. checksums.yaml +4 -4
  2. data/app/assets/stylesheets/katello/katello.scss +3 -7
  3. data/app/controllers/katello/api/rhsm/candlepin_proxies_controller.rb +1 -1
  4. data/app/controllers/katello/api/v2/activation_keys_controller.rb +8 -0
  5. data/app/controllers/katello/api/v2/host_subscriptions_controller.rb +10 -4
  6. data/app/controllers/katello/api/v2/host_tracer_controller.rb +33 -8
  7. data/app/controllers/katello/api/v2/hosts_bulk_actions_controller.rb +11 -11
  8. data/app/controllers/katello/api/v2/products_bulk_actions_controller.rb +0 -15
  9. data/app/controllers/katello/api/v2/repositories_controller.rb +5 -11
  10. data/app/controllers/katello/api/v2/upstream_subscriptions_controller.rb +16 -0
  11. data/app/controllers/katello/concerns/api/v2/bulk_hosts_extensions.rb +4 -4
  12. data/app/controllers/katello/concerns/api/v2/hostgroups_controller_extensions.rb +1 -1
  13. data/app/controllers/katello/concerns/hosts_controller_extensions.rb +5 -11
  14. data/app/helpers/katello/concerns/dashboard_helper_extensions.rb +10 -0
  15. data/app/helpers/katello/hosts_and_hostgroups_helper.rb +6 -7
  16. data/app/lib/actions/candlepin/product/content_add.rb +2 -1
  17. data/app/lib/actions/candlepin/product/content_update_enablement.rb +18 -0
  18. data/app/lib/actions/katello/applicability/hosts/bulk_generate.rb +2 -6
  19. data/app/lib/actions/katello/capsule_content/refresh_repos.rb +1 -1
  20. data/app/lib/actions/katello/capsule_content/sync.rb +1 -1
  21. data/app/lib/actions/katello/capsule_content/sync_capsule.rb +3 -17
  22. data/app/lib/actions/katello/content_view_version/incremental_update.rb +2 -3
  23. data/app/lib/actions/katello/organization/simple_content_access/disable.rb +17 -0
  24. data/app/lib/actions/katello/organization/simple_content_access/enable.rb +17 -0
  25. data/app/lib/actions/katello/organization/simple_content_access/toggle.rb +36 -0
  26. data/app/lib/actions/katello/orphan_cleanup/remove_orphans.rb +13 -0
  27. data/app/lib/actions/katello/product/content_create.rb +3 -3
  28. data/app/lib/actions/katello/product/destroy.rb +4 -25
  29. data/app/lib/actions/katello/repository/content_update.rb +41 -0
  30. data/app/lib/actions/katello/repository/destroy.rb +1 -5
  31. data/app/lib/actions/katello/repository/export.rb +1 -1
  32. data/app/lib/actions/katello/repository/multi_clone_contents.rb +15 -13
  33. data/app/lib/actions/katello/repository/sync.rb +25 -35
  34. data/app/lib/actions/katello/repository/update.rb +19 -30
  35. data/app/lib/actions/katello/repository/update_cv_repo_cert_guard.rb +17 -0
  36. data/app/lib/actions/pulp/orchestration/repository/smart_proxy_sync.rb +1 -0
  37. data/app/lib/actions/pulp/orchestration/repository/sync.rb +1 -2
  38. data/app/lib/actions/pulp/repository/sync.rb +1 -2
  39. data/app/lib/actions/pulp3/abstract_async_task.rb +0 -1
  40. data/app/lib/actions/pulp3/capsule_content/sync.rb +1 -3
  41. data/app/lib/actions/pulp3/content_view/delete_repository_references.rb +1 -1
  42. data/app/lib/actions/pulp3/orchestration/repository/copy_all_units.rb +2 -1
  43. data/app/lib/actions/pulp3/orchestration/repository/sync.rb +1 -3
  44. data/app/lib/actions/pulp3/repository/copy_content.rb +1 -0
  45. data/app/lib/actions/pulp3/repository/delete.rb +1 -1
  46. data/app/lib/actions/pulp3/repository/multi_copy_content.rb +1 -1
  47. data/app/lib/actions/pulp3/repository/save_version.rb +16 -20
  48. data/app/lib/actions/pulp3/repository/sync.rb +1 -1
  49. data/app/lib/actions/pulp3/repository/update_cv_repository_cert_guard.rb +2 -6
  50. data/app/lib/actions/pulp3/repository/upload_file.rb +1 -1
  51. data/app/lib/katello/resources/candlepin/product.rb +11 -0
  52. data/app/lib/katello/resources/cdn.rb +2 -3
  53. data/app/lib/katello/util/cdn_var_substitutor.rb +7 -9
  54. data/app/lib/katello/validators/hostgroup_kickstart_repository_validator.rb +11 -11
  55. data/app/models/katello/activation_key.rb +1 -1
  56. data/app/models/katello/concerns/content_facet_host_extensions.rb +7 -0
  57. data/app/models/katello/concerns/host_managed_extensions.rb +39 -0
  58. data/app/models/katello/concerns/hostgroup_extensions.rb +46 -24
  59. data/app/models/katello/concerns/smart_proxy_extensions.rb +5 -19
  60. data/app/models/katello/concerns/widget_extensions.rb +23 -0
  61. data/app/models/katello/content_view.rb +9 -1
  62. data/app/models/katello/content_view_package_filter.rb +1 -1
  63. data/app/models/katello/content_view_version.rb +7 -0
  64. data/app/models/katello/erratum.rb +13 -0
  65. data/app/models/katello/erratum_cve.rb +8 -0
  66. data/app/models/katello/glue/pulp/repo.rb +1 -1
  67. data/app/models/katello/host/content_facet.rb +18 -1
  68. data/app/models/katello/host_collection.rb +6 -0
  69. data/app/models/katello/hostgroup/content_facet.rb +18 -0
  70. data/app/models/katello/installed_package.rb +8 -0
  71. data/app/models/katello/kt_environment.rb +9 -1
  72. data/app/models/katello/model.rb +16 -0
  73. data/app/models/katello/pool.rb +17 -0
  74. data/app/models/katello/product.rb +6 -0
  75. data/app/models/katello/purpose_addons_status.rb +1 -0
  76. data/app/models/katello/purpose_role_status.rb +1 -0
  77. data/app/models/katello/purpose_sla_status.rb +1 -0
  78. data/app/models/katello/purpose_usage_status.rb +1 -0
  79. data/app/models/katello/repository.rb +3 -6
  80. data/app/models/katello/root_repository.rb +24 -16
  81. data/app/models/katello/subscription_status.rb +1 -1
  82. data/app/models/katello/trace_status.rb +1 -1
  83. data/app/models/setting/content.rb +6 -2
  84. data/app/services/cert/certs.rb +2 -10
  85. data/app/services/katello/event_daemon.rb +7 -8
  86. data/app/services/katello/host_status_manager.rb +13 -0
  87. data/app/services/katello/pulp3/migration.rb +1 -1
  88. data/app/services/katello/pulp3/repository/yum.rb +6 -72
  89. data/app/services/katello/pulp3/repository.rb +11 -10
  90. data/app/services/katello/pulp3/smart_proxy_mirror_repository.rb +1 -1
  91. data/app/services/katello/pulp3/task.rb +3 -3
  92. data/app/services/katello/pulp3/task_group.rb +0 -6
  93. data/app/services/katello/smart_proxy_helper.rb +16 -13
  94. data/app/views/foreman/smart_proxies/_content_sync.html.erb +1 -1
  95. data/app/views/katello/api/v2/repositories/base.json.rabl +1 -1
  96. data/config/routes/api/rhsm.rb +0 -1
  97. data/config/routes/api/v2.rb +8 -2
  98. data/config/routes/overrides.rb +0 -4
  99. data/db/migrate/20141222151001_add_host_content_view_environment.rb +1 -1
  100. data/db/migrate/20180904122343_create_hostgroup_content_facet.katello.rb +16 -0
  101. data/db/migrate/20200514092553_move_katello_fields_from_hostgroups.katello.rb +53 -0
  102. data/db/migrate/20200610112009_remove_audits_of_root_repo_with_content_id.rb +9 -0
  103. data/db/migrate/20200701150946_add_auto_enabled_to_root_repository.rb +5 -0
  104. data/db/seeds.d/75-job_templates.rb +2 -2
  105. data/engines/bastion/app/assets/javascripts/bastion/components/nutupane.factory.js +3 -1
  106. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/activation-keys/details/activation-key-associations.controller.js +5 -2
  107. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/activation-keys/details/activation-key-details.controller.js +4 -2
  108. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/activation-keys/details/views/activation-key-add-subscriptions.html +1 -1
  109. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/activation-keys/details/views/activation-key-associations-content-hosts.html +2 -2
  110. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/activation-keys/details/views/activation-key-details.html +1 -1
  111. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/content-hosts/bulk/content-hosts-bulk-errata-modal.controller.js +4 -1
  112. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/content-hosts/bulk/content-hosts-bulk-packages-modal.controller.js +4 -1
  113. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/content-hosts/bulk/content-hosts-bulk-subscriptions-modal.controller.js +1 -0
  114. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/content-hosts/bulk/content-hosts-bulk-traces-modal.controller.js +4 -3
  115. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/content-hosts/bulk/views/content-hosts-bulk-environment-modal.html +7 -1
  116. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/content-hosts/bulk/views/content-hosts-bulk-errata-modal.html +1 -0
  117. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/content-hosts/bulk/views/content-hosts-bulk-packages-modal.html +1 -0
  118. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/content-hosts/content-hosts.controller.js +4 -2
  119. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/content-hosts/content-hosts.routes.js +1 -1
  120. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/content-hosts/details/content-host-details-info.controller.js +7 -1
  121. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/content-hosts/details/content-host-details.controller.js +4 -2
  122. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/content-hosts/details/views/content-host-add-subscriptions.html +1 -1
  123. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/content-hosts/details/views/content-host-details.html +1 -0
  124. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/content-hosts/details/views/content-host-info.html +14 -6
  125. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/content-hosts/details/views/content-host-subscriptions-list.html +1 -1
  126. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/content-hosts/views/content-hosts.html +6 -6
  127. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/host-collections/details/host-collection-details.controller.js +5 -2
  128. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/host-collections/details/views/host-collection-info.html +1 -1
  129. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/hosts/host-bulk-action.factory.js +1 -2
  130. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/hosts/host-traces-resolve.factory.js +18 -0
  131. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/i18n/bastion_katello.pot +45 -4
  132. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/i18n/locale/de.po +1 -1
  133. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/i18n/locale/es.po +1 -1
  134. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/i18n/locale/fr.po +1 -1
  135. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/i18n/locale/it.po +1 -1
  136. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/i18n/locale/ja.po +1 -1
  137. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/i18n/locale/ko.po +1 -1
  138. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/i18n/locale/pt_BR.po +1 -1
  139. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/i18n/locale/ru.po +1 -1
  140. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/i18n/locale/zh_CN.po +1 -1
  141. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/i18n/locale/zh_TW.po +1 -1
  142. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/products/bulk/product-bulk-action.factory.js +0 -1
  143. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/products/details/repositories/details/repository-details.controller.js +0 -6
  144. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/products/details/repositories/details/views/repository-details.html +1 -7
  145. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/products/details/repositories/details/views/repository-info.html +11 -1
  146. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/products/details/repositories/new/new-repository.controller.js +1 -1
  147. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/products/details/repositories/new/views/new-repository.html +16 -4
  148. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/products/details/repositories/repository.factory.js +0 -1
  149. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/products/products.controller.js +0 -15
  150. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/products/views/products.html +0 -6
  151. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/subscriptions/views/content-access-mode-banner.html +1 -1
  152. data/lib/katello/engine.rb +6 -5
  153. data/lib/katello/permission_creator.rb +3 -3
  154. data/lib/katello/permissions/host_permissions.rb +0 -1
  155. data/lib/katello/plugin.rb +20 -16
  156. data/lib/katello/tasks/pulp3_post_migration_check.rake +1 -2
  157. data/lib/katello/tasks/reimport.rake +1 -1
  158. data/lib/katello/tasks/reports.rake +0 -12
  159. data/lib/katello/tasks/test.rake +15 -0
  160. data/lib/katello/version.rb +1 -1
  161. data/locale/action_names.rb +48 -48
  162. data/locale/bn/katello.po +137 -14
  163. data/locale/cs/katello.po +137 -14
  164. data/locale/de/katello.po +138 -15
  165. data/locale/en/katello.po +137 -14
  166. data/locale/es/katello.po +138 -15
  167. data/locale/fr/katello.po +138 -15
  168. data/locale/gu/katello.po +137 -14
  169. data/locale/hi/katello.po +137 -14
  170. data/locale/it/katello.po +138 -15
  171. data/locale/ja/katello.po +138 -15
  172. data/locale/katello.pot +969 -769
  173. data/locale/kn/katello.po +137 -14
  174. data/locale/ko/katello.po +138 -15
  175. data/locale/mr/katello.po +137 -14
  176. data/locale/or/katello.po +137 -14
  177. data/locale/pa/katello.po +137 -14
  178. data/locale/pt/katello.po +137 -14
  179. data/locale/pt_BR/katello.po +138 -15
  180. data/locale/ru/katello.po +138 -15
  181. data/locale/ta/katello.po +137 -14
  182. data/locale/te/katello.po +137 -14
  183. data/locale/zh_CN/katello.po +138 -15
  184. data/locale/zh_TW/katello.po +138 -15
  185. data/package.json +8 -25
  186. data/webpack/__mocks__/foremanReact/Root/Context/ForemanContext.js +3 -0
  187. data/webpack/components/ActionableDetail.js +63 -0
  188. data/webpack/components/Content/ContentTable.js +2 -2
  189. data/webpack/components/Content/Details/ContentDetailRepositoryTableSchema.js +1 -1
  190. data/webpack/components/Content/Details/ContentDetails.js +1 -1
  191. data/webpack/components/Content/__tests__/ContentTable.test.js +2 -2
  192. data/webpack/components/Content/__tests__/__snapshots__/ContentPage.test.js.snap +1 -1
  193. data/webpack/components/EditableSwitch.js +30 -0
  194. data/webpack/components/EditableTextInput/EditableTextInput.js +120 -0
  195. data/webpack/components/EditableTextInput/__tests__/editableTextInput.test.js +52 -0
  196. data/webpack/components/EditableTextInput/editableTextInput.scss +14 -0
  197. data/webpack/components/EditableTextInput/index.js +3 -0
  198. data/webpack/{scenes/ContentViews/components → components}/Loading.js +8 -5
  199. data/webpack/{move_to_pf → components}/LoadingState/LoadingState.js +0 -0
  200. data/webpack/{move_to_pf → components}/LoadingState/LoadingState.scss +0 -0
  201. data/webpack/{move_to_pf → components}/LoadingState/LoadingState.test.js +0 -0
  202. data/webpack/{move_to_pf → components}/LoadingState/__snapshots__/LoadingState.test.js.snap +0 -0
  203. data/webpack/{move_to_pf → components}/LoadingState/index.js +0 -0
  204. data/webpack/components/MultiSelect/index.js +1 -1
  205. data/webpack/{move_to_pf → components}/OptionTooltip/OptionTooltip.scss +0 -0
  206. data/webpack/{move_to_pf → components}/OptionTooltip/__tests__/OptionTooltip.test.js +0 -0
  207. data/webpack/{move_to_pf → components}/OptionTooltip/__tests__/__snapshots__/OptionTooltip.test.js.snap +0 -0
  208. data/webpack/{move_to_pf → components}/OptionTooltip/index.js +0 -0
  209. data/webpack/components/Search/Search.js +124 -0
  210. data/webpack/components/Search/Search.test.js +2 -1
  211. data/webpack/components/Search/__snapshots__/Search.test.js.snap +2 -0
  212. data/webpack/components/Search/__tests__/search.test.js +124 -0
  213. data/webpack/components/Search/index.js +11 -87
  214. data/webpack/{move_to_pf → components}/Select/Select.js +0 -0
  215. data/webpack/components/SelectOrg/SetOrganization.js +2 -2
  216. data/webpack/components/TabWrapper/TabWrapper.js +26 -0
  217. data/webpack/components/TabWrapper/index.js +3 -0
  218. data/webpack/components/TabbedView/TabbedView.js +38 -0
  219. data/webpack/components/TabbedView/TabbedView.scss +3 -0
  220. data/webpack/components/TabbedView/index.js +3 -0
  221. data/webpack/components/Table/EmptyStateMessage.js +61 -0
  222. data/webpack/{scenes/ContentViews/Table/TableWrapper.js → components/Table/MainTable.js} +23 -12
  223. data/webpack/components/Table/TableWrapper.js +94 -0
  224. data/webpack/{move_to_pf → components}/TooltipButton/TooltipButton.js +0 -0
  225. data/webpack/{move_to_pf → components}/TooltipButton/TooltipButton.scss +0 -0
  226. data/webpack/{move_to_pf → components}/TooltipButton/TooltipButton.test.js +0 -0
  227. data/webpack/{move_to_pf → components}/TooltipButton/__snapshots__/TooltipButton.test.js.snap +0 -0
  228. data/webpack/{move_to_pf → components}/TooltipButton/index.js +0 -0
  229. data/webpack/components/TypeAhead/TypeAhead.js +109 -0
  230. data/webpack/{move_to_pf → components}/TypeAhead/TypeAhead.scss +0 -0
  231. data/webpack/components/TypeAhead/helpers/commonPropTypes.js +35 -0
  232. data/webpack/components/TypeAhead/helpers/helpers.js +32 -0
  233. data/webpack/components/TypeAhead/index.js +3 -0
  234. data/webpack/{move_to_pf/TypeAhead → components/TypeAhead/pf3Search}/TypeAheadInput.js +3 -6
  235. data/webpack/{move_to_pf/TypeAhead → components/TypeAhead/pf3Search}/TypeAheadItems.js +3 -7
  236. data/webpack/components/TypeAhead/pf3Search/TypeAheadSearch.js +52 -0
  237. data/webpack/components/TypeAhead/pf4Search/TypeAheadInput.js +44 -0
  238. data/webpack/components/TypeAhead/pf4Search/TypeAheadInput.scss +11 -0
  239. data/webpack/components/TypeAhead/pf4Search/TypeAheadItems.js +57 -0
  240. data/webpack/components/TypeAhead/pf4Search/TypeAheadSearch.js +66 -0
  241. data/webpack/components/TypeAhead/pf4Search/TypeAheadSearch.scss +5 -0
  242. data/webpack/components/extensions/about/__tests__/SystemStatuses.test.js +1 -1
  243. data/webpack/{move_to_foreman/components/common/table → components/pf3Table}/components/CollapseSubscriptionGroupButton.js +0 -0
  244. data/webpack/{move_to_foreman/components/common/table → components/pf3Table}/components/CollapseSubscriptionGroupButton.test.js +0 -0
  245. data/webpack/{move_to_foreman/components/common/table → components/pf3Table}/components/Table.js +0 -0
  246. data/webpack/{move_to_foreman/components/common/table → components/pf3Table}/components/Table.test.js +0 -0
  247. data/webpack/{move_to_foreman/components/common/table → components/pf3Table}/components/TableBody.js +0 -0
  248. data/webpack/{move_to_foreman/components/common/table → components/pf3Table}/components/TableBody.test.js +0 -0
  249. data/webpack/{move_to_foreman/components/common/table → components/pf3Table}/components/TableBodyMessage.js +0 -0
  250. data/webpack/{move_to_foreman/components/common/table → components/pf3Table}/components/TableBodyMessage.test.js +0 -0
  251. data/webpack/{move_to_foreman/components/common/table → components/pf3Table}/components/TableFixtures.js +0 -0
  252. data/webpack/{move_to_foreman/components/common/table → components/pf3Table}/components/TableSelectionCell.js +0 -0
  253. data/webpack/{move_to_foreman/components/common/table → components/pf3Table}/components/TableSelectionCell.test.js +0 -0
  254. data/webpack/{move_to_foreman/components/common/table → components/pf3Table}/components/TableSelectionHeaderCell.js +0 -0
  255. data/webpack/{move_to_foreman/components/common/table → components/pf3Table}/components/TableSelectionHeaderCell.test.js +0 -0
  256. data/webpack/{move_to_foreman/components/common/table → components/pf3Table}/components/__snapshots__/CollapseSubscriptionGroupButton.test.js.snap +0 -0
  257. data/webpack/{move_to_foreman/components/common/table → components/pf3Table}/components/__snapshots__/Table.test.js.snap +0 -0
  258. data/webpack/{move_to_foreman/components/common/table → components/pf3Table}/components/__snapshots__/TableBody.test.js.snap +0 -0
  259. data/webpack/{move_to_foreman/components/common/table → components/pf3Table}/components/__snapshots__/TableBodyMessage.test.js.snap +0 -0
  260. data/webpack/{move_to_foreman/components/common/table → components/pf3Table}/components/__snapshots__/TableSelectionCell.test.js.snap +0 -0
  261. data/webpack/{move_to_foreman/components/common/table → components/pf3Table}/components/__snapshots__/TableSelectionHeaderCell.test.js.snap +0 -0
  262. data/webpack/{move_to_foreman/components/common/table → components/pf3Table}/components/index.js +0 -0
  263. data/webpack/{move_to_foreman/components/common/table → components/pf3Table}/formatters/EntitlementsInlineEditFormatter.js +1 -1
  264. data/webpack/{move_to_foreman/components/common/table → components/pf3Table}/formatters/__tests__/EntitlementsInlineEditFormatter.test.js +0 -0
  265. data/webpack/{move_to_foreman/components/common/table → components/pf3Table}/formatters/__tests__/__snapshots__/EntitlementsInlineEditFormatter.test.js.snap +0 -0
  266. data/webpack/{move_to_foreman/components/common/table → components/pf3Table}/formatters/cellFormatter.js +0 -0
  267. data/webpack/{move_to_foreman/components/common/table → components/pf3Table}/formatters/collapseableAndSelectionCellFormatter.js +0 -0
  268. data/webpack/{move_to_foreman/components/common/table → components/pf3Table}/formatters/ellipsisCellFormatter.js +0 -0
  269. data/webpack/{move_to_foreman/components/common/table → components/pf3Table}/formatters/headerFormatter.js +0 -0
  270. data/webpack/{move_to_foreman/components/common/table → components/pf3Table}/formatters/index.js +0 -0
  271. data/webpack/{move_to_foreman/components/common/table → components/pf3Table}/formatters/selectionCellFormatter.js +0 -0
  272. data/webpack/{move_to_foreman/components/common/table → components/pf3Table}/formatters/selectionHeaderCellFormatter.js +0 -0
  273. data/webpack/{move_to_foreman/components/common/table → components/pf3Table}/index.js +0 -0
  274. data/webpack/{move_to_pf → components}/react-bootstrap-select/index.js +0 -0
  275. data/webpack/containers/Application/config.js +5 -0
  276. data/webpack/containers/Application/overrides.scss +5 -0
  277. data/webpack/global_test_setup.js +3 -1
  278. data/webpack/redux/OrganizationProducts/OrganizationProductsActions.js +1 -1
  279. data/webpack/redux/OrganizationProducts/__tests__/OrganizationProductsActions.test.js +2 -2
  280. data/webpack/redux/actions/RedHatRepositories/enabled.js +1 -1
  281. data/webpack/redux/actions/RedHatRepositories/helpers.js +1 -1
  282. data/webpack/redux/actions/RedHatRepositories/repositorySetRepositories.js +1 -1
  283. data/webpack/redux/reducers/index.js +2 -0
  284. data/webpack/scenes/AnsibleCollections/AnsibleCollectionsActions.js +1 -1
  285. data/webpack/scenes/AnsibleCollections/AnsibleCollectionsTableSchema.js +1 -1
  286. data/webpack/scenes/AnsibleCollections/Details/AnsibleCollectionDetailsActions.js +1 -1
  287. data/webpack/scenes/AnsibleCollections/Details/__tests__/AnsibleCollectionDetailsActions.test.js +2 -2
  288. data/webpack/scenes/AnsibleCollections/__tests__/AnsibleCollectionsTable.test.js +1 -1
  289. data/webpack/scenes/ContentViews/ContentViewSelectors.js +1 -2
  290. data/webpack/scenes/ContentViews/ContentViewsActions.js +4 -4
  291. data/webpack/scenes/ContentViews/ContentViewsConstants.js +4 -1
  292. data/webpack/scenes/ContentViews/ContentViewsPage.js +12 -6
  293. data/webpack/scenes/ContentViews/Details/ContentViewDetailActions.js +44 -0
  294. data/webpack/scenes/ContentViews/Details/ContentViewDetailReducer.js +23 -0
  295. data/webpack/scenes/ContentViews/{details → Details}/ContentViewDetailSelectors.js +3 -0
  296. data/webpack/scenes/ContentViews/Details/ContentViewDetails.js +70 -0
  297. data/webpack/scenes/ContentViews/Details/ContentViewInfo.js +116 -0
  298. data/webpack/scenes/ContentViews/{details → Details}/DetailsContainer.js +8 -4
  299. data/webpack/scenes/ContentViews/Details/__tests__/contentViewDetail.test.js +101 -0
  300. data/webpack/scenes/ContentViews/Details/__tests__/contentViewDetails.fixtures.json +106 -0
  301. data/webpack/scenes/ContentViews/Details/contentViewInfo.scss +8 -0
  302. data/webpack/scenes/ContentViews/Details/index.js +7 -0
  303. data/webpack/scenes/ContentViews/Table/ContentViewsTable.js +51 -36
  304. data/webpack/scenes/ContentViews/Table/tableDataGenerator.js +47 -44
  305. data/webpack/scenes/ContentViews/__tests__/basicContentViews.fixtures.js +31 -0
  306. data/webpack/scenes/ContentViews/__tests__/contentViewList.fixtures.json +2 -1
  307. data/webpack/scenes/ContentViews/__tests__/contentViewPage.test.js +173 -23
  308. data/webpack/scenes/ContentViews/components/ContentViewIcon.js +26 -0
  309. data/webpack/scenes/ContentViews/components/{contentViewName.scss → contentViewIcon.scss} +0 -0
  310. data/webpack/scenes/ModuleStreams/Details/ModuleStreamDetailsActions.js +1 -1
  311. data/webpack/scenes/ModuleStreams/Details/Profiles/TableSchema.js +1 -1
  312. data/webpack/scenes/ModuleStreams/Details/__tests__/ModuleStreamDetailsActions.test.js +2 -2
  313. data/webpack/scenes/ModuleStreams/ModuleStreamsActions.js +1 -1
  314. data/webpack/scenes/ModuleStreams/ModuleStreamsTableSchema.js +1 -1
  315. data/webpack/scenes/ModuleStreams/__tests__/ModuleStreamsTable.test.js +1 -1
  316. data/webpack/scenes/Organizations/OrganizationSelectors.js +14 -0
  317. data/webpack/scenes/Products/ProductActions.js +1 -1
  318. data/webpack/scenes/RedHatRepositories/RedHatRepositoriesPage.js +1 -1
  319. data/webpack/scenes/Settings/SettingsConstants.js +3 -0
  320. data/webpack/scenes/Settings/SettingsReducer.js +33 -0
  321. data/webpack/scenes/Settings/SettingsSelectors.js +4 -0
  322. data/webpack/scenes/Settings/index.js +2 -1
  323. data/webpack/scenes/Subscriptions/Details/SubscriptionDetailActions.js +1 -1
  324. data/webpack/scenes/Subscriptions/Details/SubscriptionDetails.js +1 -1
  325. data/webpack/scenes/Subscriptions/Manifest/ManageManifestModal.js +59 -73
  326. data/webpack/scenes/Subscriptions/Manifest/ManageManifestModal.scss +15 -0
  327. data/webpack/scenes/Subscriptions/Manifest/ManifestActions.js +43 -1
  328. data/webpack/scenes/Subscriptions/Manifest/ManifestConstants.js +8 -0
  329. data/webpack/scenes/Subscriptions/Manifest/ManifestHistoryTableSchema.js +1 -1
  330. data/webpack/scenes/Subscriptions/Manifest/SimpleContentAccess.js +78 -0
  331. data/webpack/scenes/Subscriptions/Manifest/__tests__/ManageManifestModal.test.js +2 -0
  332. data/webpack/scenes/Subscriptions/Manifest/__tests__/ManifestActions.test.js +56 -1
  333. data/webpack/scenes/Subscriptions/Manifest/__tests__/SimpleContentAccess.test.js +114 -0
  334. data/webpack/scenes/Subscriptions/Manifest/__tests__/__snapshots__/ManageManifestModal.test.js.snap +6 -6
  335. data/webpack/scenes/Subscriptions/Manifest/__tests__/manifest.fixtures.js +36 -0
  336. data/webpack/scenes/Subscriptions/Manifest/index.js +3 -1
  337. data/webpack/scenes/Subscriptions/SubscriptionActions.js +1 -1
  338. data/webpack/scenes/Subscriptions/SubscriptionConstants.js +4 -0
  339. data/webpack/scenes/Subscriptions/SubscriptionHelpers.js +0 -3
  340. data/webpack/scenes/Subscriptions/SubscriptionReducer.js +38 -11
  341. data/webpack/scenes/Subscriptions/SubscriptionsPage.js +30 -18
  342. data/webpack/scenes/Subscriptions/SubscriptionsSelectors.js +0 -3
  343. data/webpack/scenes/Subscriptions/UpstreamSubscriptions/UpstreamSubscriptionsActions.js +1 -1
  344. data/webpack/scenes/Subscriptions/UpstreamSubscriptions/UpstreamSubscriptionsPage.js +2 -2
  345. data/webpack/scenes/Subscriptions/UpstreamSubscriptions/UpstreamSubscriptionsTableSchema.js +1 -1
  346. data/webpack/scenes/Subscriptions/__tests__/SubscriptionHelpers.test.js +0 -11
  347. data/webpack/scenes/Subscriptions/__tests__/__snapshots__/SubscriptionsActions.test.js.snap +2 -2
  348. data/webpack/scenes/Subscriptions/__tests__/__snapshots__/SubscriptionsPage.test.js.snap +4 -4
  349. data/webpack/scenes/Subscriptions/__tests__/__snapshots__/SubscriptionsReducer.test.js.snap +26 -1
  350. data/webpack/scenes/Subscriptions/components/SubscriptionsTable/SubscriptionTypeFormatter.js +2 -2
  351. data/webpack/scenes/Subscriptions/components/SubscriptionsTable/SubscriptionsTable.js +27 -21
  352. data/webpack/scenes/Subscriptions/components/SubscriptionsTable/SubscriptionsTableHelpers.js +6 -2
  353. data/webpack/scenes/Subscriptions/components/SubscriptionsTable/SubscriptionsTableSchema.js +2 -2
  354. data/webpack/scenes/Subscriptions/components/SubscriptionsTable/__tests__/__snapshots__/SubscriptionTypeFormatter.test.js.snap +3 -3
  355. data/webpack/scenes/Subscriptions/components/SubscriptionsTable/components/Table.js +1 -1
  356. data/webpack/scenes/Subscriptions/components/SubscriptionsToolbar/SubscriptionsToolbar.js +28 -3
  357. data/webpack/scenes/Subscriptions/components/SubscriptionsToolbar/__snapshots__/SubscriptionsToolbar.test.js.snap +5 -10
  358. data/webpack/scenes/Subscriptions/index.js +6 -2
  359. data/webpack/test-utils/nockWrapper.js +39 -5
  360. data/webpack/test-utils/react-testing-lib-wrapper.js +35 -9
  361. data/webpack/{move_to_foreman/common → utils}/helpers.js +12 -8
  362. data/webpack/utils/useEventListener.js +37 -0
  363. metadata +143 -83
  364. data/app/lib/actions/katello/repository/verify_checksum.rb +0 -28
  365. data/app/lib/actions/pulp3/orchestration/repository/trigger_update_repo_cert_guard.rb +0 -22
  366. data/app/lib/actions/pulp3/repository/presenters/repair_presenter.rb +0 -85
  367. data/app/lib/actions/pulp3/repository/repair.rb +0 -29
  368. data/app/services/katello/host_trace_manager.rb +0 -38
  369. data/vendor/assets/stylesheets/katello/jquery.loadmask.css.scss +0 -40
  370. data/vendor/assets/stylesheets/katello/ui.spinner.css.scss +0 -3
  371. data/webpack/__mocks__/foremanReact/components/ForemanModal/ForemanModalActions.js +0 -2
  372. data/webpack/__mocks__/foremanReact/components/ForemanModal/ForemanModalSelectors.js +0 -2
  373. data/webpack/__mocks__/foremanReact/components/ForemanModal/index.js +0 -4
  374. data/webpack/__mocks__/foremanReact/components/Settings/SettingsActions.js +0 -4
  375. data/webpack/__mocks__/foremanReact/components/Settings/SettingsConstants.js +0 -2
  376. data/webpack/move_to_pf/TypeAhead/TypeAhead.js +0 -138
  377. data/webpack/move_to_pf/TypeAhead/helpers.js +0 -5
  378. data/webpack/scenes/ContentViews/components/ContentViewName.js +0 -33
  379. data/webpack/scenes/ContentViews/components/EmptyStateMessage.js +0 -43
  380. data/webpack/scenes/ContentViews/details/ContentViewDetailActions.js +0 -12
  381. data/webpack/scenes/ContentViews/expansions/RepositoriesExpansion.js +0 -12
@@ -1,39 +1,40 @@
1
1
  import React from 'react';
2
- import { compoundExpand } from '@patternfly/react-table';
3
- import { ScreenIcon, RepositoryIcon, ContainerNodeIcon } from '@patternfly/react-icons';
2
+ import { compoundExpand, fitContent } from '@patternfly/react-table';
3
+ import {
4
+ ScreenIcon,
5
+ ContainerNodeIcon,
6
+ } from '@patternfly/react-icons';
7
+ import { Link } from 'react-router-dom';
8
+ import { urlBuilder } from 'foremanReact/common/urlHelpers';
4
9
  import { translate as __ } from 'foremanReact/common/I18n';
5
10
 
6
11
  import IconWithCount from '../components/IconWithCount';
7
12
  import DetailsExpansion from '../expansions/DetailsExpansion';
8
- import RepositoriesExpansion from '../expansions/RepositoriesExpansion';
9
13
  import EnvironmentsExpansion from '../expansions/EnvironmentsExpansion';
10
14
  import VersionsExpansion from '../expansions/VersionsExpansion';
11
- import ContentViewName from '../components/ContentViewName';
12
- import DetailsContainer from '../details/DetailsContainer';
15
+ import ContentViewIcon from '../components/ContentViewIcon';
16
+ import DetailsContainer from '../Details/DetailsContainer';
13
17
 
14
18
  export const buildColumns = () => [
19
+ { title: __('Type'), transforms: [fitContent] },
15
20
  __('Name'), __('Last published'), __('Details'),
16
21
  { title: __('Environments'), cellTransforms: [compoundExpand] },
17
- { title: __('Repositories'), cellTransforms: [compoundExpand] },
18
22
  { title: __('Versions'), cellTransforms: [compoundExpand] },
19
23
  ];
20
24
 
21
25
  const buildRow = (contentView, openColumn) => {
22
26
  const {
23
- id, composite, name, environments, repositories, versions, last_published: lastPublished,
27
+ id, composite, name, environments, versions, last_published: lastPublished,
24
28
  } = contentView;
25
29
  const row = [
26
- { title: <ContentViewName composite={composite ? true : undefined} name={name} cvId={id} /> },
30
+ { title: <ContentViewIcon composite={composite ? true : undefined} /> },
31
+ { title: <Link to={urlBuilder('labs/content_views', '', id)}>{name}</Link> },
27
32
  lastPublished || 'Not yet published',
28
33
  { title: __('Details'), props: { isOpen: false, ariaControls: `cv-details-expansion-${id}` } },
29
34
  {
30
35
  title: <IconWithCount Icon={ScreenIcon} count={environments.length} title={`environments-icon-${id}`} />,
31
36
  props: { isOpen: false, ariaControls: `cv-environments-expansion-${id}` },
32
37
  },
33
- {
34
- title: <IconWithCount Icon={RepositoryIcon} count={repositories.length} title={`repositories-icon-${id}`} />,
35
- props: { isOpen: false, ariaControls: `cv-repositories-expansion-${id}` },
36
- },
37
38
  {
38
39
  title: <IconWithCount Icon={ContainerNodeIcon} count={versions.length} title={`versions-icon-${id}`} />,
39
40
  props: { isOpen: false, ariaControls: `cv-versions-expansion-${id}` },
@@ -48,14 +49,15 @@ const buildDetailDropdowns = (id, rowIndex, openColumn) => {
48
49
  const cvId = { cvId: id };
49
50
  const expansionProps = { ...cvId, className: 'pf-m-no-padding' };
50
51
  const containerProps = column => ({ ...cvId, isOpen: openColumn === column });
52
+ const offsetColumn = 3; // index of first expandable column
51
53
 
52
54
  let detailDropdowns = [
53
55
  {
54
- compoundParent: 2,
56
+ compoundParent: offsetColumn,
55
57
  cells: [
56
58
  {
57
59
  title: (
58
- <DetailsContainer {...containerProps(3)}>
60
+ <DetailsContainer {...containerProps(offsetColumn + 1)}>
59
61
  <DetailsExpansion {...expansionProps} />
60
62
  </DetailsContainer>),
61
63
  props: { colSpan: 6 },
@@ -63,11 +65,11 @@ const buildDetailDropdowns = (id, rowIndex, openColumn) => {
63
65
  ],
64
66
  },
65
67
  {
66
- compoundParent: 3,
68
+ compoundParent: offsetColumn + 1,
67
69
  cells: [
68
70
  {
69
71
  title: (
70
- <DetailsContainer {...containerProps(4)}>
72
+ <DetailsContainer {...containerProps(offsetColumn + 2)}>
71
73
  <EnvironmentsExpansion {...expansionProps} />
72
74
  </DetailsContainer>),
73
75
  props: { colSpan: 6 },
@@ -75,23 +77,11 @@ const buildDetailDropdowns = (id, rowIndex, openColumn) => {
75
77
  ],
76
78
  },
77
79
  {
78
- compoundParent: 4,
79
- cells: [
80
- {
81
- title: (
82
- <DetailsContainer {...containerProps(5)}>
83
- <RepositoriesExpansion {...expansionProps} />
84
- </DetailsContainer>),
85
- props: { colSpan: 6 },
86
- },
87
- ],
88
- },
89
- {
90
- compoundParent: 5,
80
+ compoundParent: offsetColumn + 2,
91
81
  cells: [
92
82
  {
93
83
  title: (
94
- <DetailsContainer {...containerProps(6)}>
84
+ <DetailsContainer {...containerProps(offsetColumn + 3)}>
95
85
  <VersionsExpansion {...expansionProps} />
96
86
  </DetailsContainer>),
97
87
  props: { colSpan: 6 },
@@ -100,26 +90,22 @@ const buildDetailDropdowns = (id, rowIndex, openColumn) => {
100
90
  },
101
91
  ];
102
92
 
103
- // The rows are indexed along with the hidden dropdown rows, so we need to offset the parent row
104
- const rowOffset = detailDropdowns.length + 1;
105
- detailDropdowns = detailDropdowns.map(detail => ({ ...detail, parent: rowIndex * rowOffset }));
93
+ detailDropdowns = detailDropdowns.map(detail => ({ ...detail, parent: rowIndex }));
106
94
 
107
95
  return detailDropdowns;
108
96
  };
109
97
 
110
- const tableDataGenerator = (results, rowMapping) => {
111
- const updatedRowMapping = { ...rowMapping };
112
- const contentViews = results || [];
113
- const columns = buildColumns();
98
+ const buildRowsAndMapping = (contentViews, newRowMapping) => {
99
+ const updatedRowMap = { ...newRowMapping };
114
100
  const rows = [];
115
101
 
116
- contentViews.forEach((contentView, rowIndex) => {
102
+ contentViews.forEach((contentView) => {
117
103
  const { id } = contentView;
118
- // hasOwnProperty syntax because of https://eslint.org/docs/rules/no-prototype-builtins
119
- if (!Object.prototype.hasOwnProperty.call(updatedRowMapping, id)) {
120
- updatedRowMapping[id] = { expandedColumn: null, rowIndex: rows.length };
121
- }
122
- const openColumn = updatedRowMapping[id].expandedColumn;
104
+ const rowIndex = rows.length;
105
+ const needsUpdate = !Object.keys(updatedRowMap).find(i => updatedRowMap[i].id === id) ||
106
+ !Object.keys(updatedRowMap[rowIndex] || {}).includes('expandedColumn');
107
+ if (needsUpdate) updatedRowMap[rowIndex] = { expandedColumn: null, id };
108
+ const openColumn = updatedRowMap[rowIndex].expandedColumn;
123
109
  const cells = buildRow(contentView, openColumn);
124
110
  const isOpen = !!openColumn;
125
111
 
@@ -127,7 +113,24 @@ const tableDataGenerator = (results, rowMapping) => {
127
113
  rows.push(...buildDetailDropdowns(id, rowIndex, openColumn));
128
114
  });
129
115
 
130
- return { updatedRowMapping, rows, columns };
116
+ return { rows, updatedRowMap };
117
+ };
118
+
119
+ const tableDataGenerator = (results, rowMapping) => {
120
+ // If a search was performed or perPage has changed, we can clear mapping
121
+ const prevRowMapping = (results.length === Object.keys(rowMapping).length) ? rowMapping : {};
122
+ const newRowMapping = {};
123
+ const contentViews = results || [];
124
+ const columns = buildColumns();
125
+ const contentViewIds = contentViews.map(cv => cv.id);
126
+
127
+ // Only keep the relevant rows to keep the table status check accurate
128
+ Object.entries(prevRowMapping).forEach(([rowId, value]) => {
129
+ if (contentViewIds.includes(value.id)) newRowMapping[rowId] = value;
130
+ });
131
+ const { updatedRowMap, rows } = buildRowsAndMapping(contentViews, newRowMapping);
132
+
133
+ return { updatedRowMap, rows, columns };
131
134
  };
132
135
 
133
136
  export default tableDataGenerator;
@@ -0,0 +1,31 @@
1
+ const buildContentView = id => ({
2
+ id,
3
+ composite: 'false',
4
+ name: `contentView${id}`,
5
+ environments: [],
6
+ repositories: [],
7
+ versions: [],
8
+ last_published: 'Not Yet Published',
9
+ });
10
+
11
+ const createBasicCVs = (amount) => {
12
+ const response = {
13
+ total: 100,
14
+ subtotal: 100,
15
+ page: 1,
16
+ per_page: 20,
17
+ error: null,
18
+ search: null,
19
+ sort: {
20
+ by: 'name',
21
+ order: 'asc',
22
+ },
23
+ results: [],
24
+ };
25
+
26
+ [...Array(amount).keys()].forEach((_, i) => response.results.push(buildContentView(i)));
27
+
28
+ return response;
29
+ };
30
+
31
+ export default createBasicCVs;
@@ -1,6 +1,7 @@
1
1
  {
2
2
  "total": 2,
3
- "subtotal": 2, "page": 1,
3
+ "subtotal": 2,
4
+ "page": 1,
4
5
  "per_page": 20,
5
6
  "error": null,
6
7
  "search": null,
@@ -1,24 +1,41 @@
1
+ /* eslint-disable no-useless-escape */
1
2
  import React from 'react';
2
- import { renderWithApiRedux, waitFor } from 'react-testing-lib-wrapper';
3
+ import { renderWithRedux, patientlyWaitFor, fireEvent } from 'react-testing-lib-wrapper';
3
4
 
4
5
  import CONTENT_VIEWS_KEY from '../ContentViewsConstants';
6
+ import { createContentViewsParams } from '../ContentViewsActions';
5
7
  import ContentViewsPage from '../../ContentViews';
6
8
  import api from '../../../services/api';
7
- import { nockInstance, assertNockRequest } from '../../../test-utils/nockWrapper';
8
-
9
+ import nock, {
10
+ nockInstance, assertNockRequest, mockAutocomplete, mockSetting,
11
+ } from '../../../test-utils/nockWrapper';
12
+ import createBasicCVs from './basicContentViews.fixtures';
9
13
 
10
14
  const cvIndexData = require('./contentViewList.fixtures.json');
11
15
 
12
16
  const cvIndexPath = api.getApiUrl('/content_views');
13
- const renderOptions = { namespace: CONTENT_VIEWS_KEY };
17
+ const autocompleteUrl = '/content_views/auto_complete_search';
18
+ const renderOptions = { apiNamespace: CONTENT_VIEWS_KEY };
14
19
 
15
20
  let firstCV;
21
+ let searchDelayScope;
22
+ let autoSearchScope;
16
23
  beforeEach(() => {
17
24
  const { results } = cvIndexData;
18
25
  [firstCV] = results;
26
+ searchDelayScope = mockSetting(nockInstance, 'autosearch_delay', 500);
27
+ autoSearchScope = mockSetting(nockInstance, 'autosearch_while_typing', true);
28
+ });
29
+
30
+ afterEach(() => {
31
+ nock.cleanAll();
32
+ assertNockRequest(searchDelayScope);
33
+ assertNockRequest(autoSearchScope);
19
34
  });
20
35
 
21
- test('Can call API for CVs and show on screen on page load', async () => {
36
+ test('Can call API for CVs and show on screen on page load', async (done) => {
37
+ const autocompleteScope = mockAutocomplete(nockInstance, autocompleteUrl);
38
+
22
39
  // Mocking API call with nock so it returns the fixture data
23
40
  const scope = nockInstance
24
41
  .get(cvIndexPath)
@@ -27,19 +44,22 @@ test('Can call API for CVs and show on screen on page load', async () => {
27
44
 
28
45
  // Using a custom rendering function that sets up both redux and react-router.
29
46
  // This allows us to use the component as it is normally used
30
- const { queryByText } = renderWithApiRedux(<ContentViewsPage />, renderOptions);
47
+ const { queryByText } = renderWithRedux(<ContentViewsPage />, renderOptions);
31
48
 
32
49
  // query* functions will return the element or null if it cannot be found
33
50
  // get* functions will return the element or throw an error if it cannot be found
34
51
  // Assert that the CV is not showing yet by searching by name and the query returning null
35
52
  expect(queryByText(firstCV.name)).toBeNull();
36
53
  // Assert that the CV name is now showing on the screen, but wait for it to appear.
37
- await waitFor(() => expect(queryByText(firstCV.name)).toBeTruthy());
54
+ await patientlyWaitFor(() => expect(queryByText(firstCV.name)).toBeTruthy());
38
55
  // Assert request was made and completed, see helper function
39
- assertNockRequest(scope);
56
+ assertNockRequest(autocompleteScope);
57
+ assertNockRequest(scope, done); // Pass jest callback to confirm test is done
40
58
  });
41
59
 
42
- test('Can handle no Content Views being present', async () => {
60
+ test('Can handle no Content Views being present', async (done) => {
61
+ const autocompleteScope = mockAutocomplete(nockInstance, autocompleteUrl);
62
+
43
63
  const noResults = {
44
64
  total: 0,
45
65
  subtotal: 0,
@@ -51,49 +71,179 @@ test('Can handle no Content Views being present', async () => {
51
71
  .get(cvIndexPath)
52
72
  .query(true)
53
73
  .reply(200, noResults);
54
- const { queryByText } = renderWithApiRedux(<ContentViewsPage />, renderOptions);
74
+ const { queryByText } = renderWithRedux(<ContentViewsPage />, renderOptions);
55
75
 
56
76
  expect(queryByText(firstCV.name)).toBeNull();
57
- await waitFor(() => expect(queryByText(/don't have any Content Views/)).toBeTruthy());
58
- assertNockRequest(scope);
77
+ await patientlyWaitFor(() => expect(queryByText(/don't have any Content Views/i)).toBeTruthy());
78
+ assertNockRequest(autocompleteScope);
79
+ assertNockRequest(scope, done);
59
80
  });
60
81
 
61
- test('Can handle errored response', async () => {
82
+ test('Can handle errored response', async (done) => {
83
+ const autocompleteScope = mockAutocomplete(nockInstance, autocompleteUrl);
62
84
  const scope = nockInstance
63
85
  .get(cvIndexPath)
64
86
  .query(true)
65
87
  .reply(500);
66
- const { queryByText } = renderWithApiRedux(<ContentViewsPage />, renderOptions);
88
+
89
+ const { queryByText } = renderWithRedux(<ContentViewsPage />, renderOptions);
67
90
 
68
91
  expect(queryByText(firstCV.name)).toBeNull();
69
- await waitFor(() => expect(queryByText(/unable to retrieve information/i)).toBeTruthy());
70
- assertNockRequest(scope);
92
+ await patientlyWaitFor(() => expect(queryByText(/unable to connect/i)).toBeTruthy());
93
+ assertNockRequest(autocompleteScope);
94
+ assertNockRequest(scope, done);
71
95
  });
72
96
 
73
- test('Can handle loading state while request is being made', () => {
97
+ test('Can handle loading state while request is being made', async (done) => {
98
+ const autocompleteScope = mockAutocomplete(nockInstance, autocompleteUrl);
74
99
  const scope = nockInstance
75
100
  .get(cvIndexPath)
76
101
  .delay(2000) // Delay the response so we can check loading state properly
77
102
  .query(true)
78
103
  .reply(200);
79
104
 
80
- const { queryByText } = renderWithApiRedux(<ContentViewsPage />, renderOptions);
105
+ const { queryByText } = renderWithRedux(<ContentViewsPage />, renderOptions);
81
106
 
82
107
  expect(queryByText('Loading')).toBeTruthy();
83
- scope.isDone(); // ensure request is cleaned up
108
+ assertNockRequest(autocompleteScope);
109
+ assertNockRequest(scope, done);
84
110
  });
85
111
 
86
- test('Can handle unpublished Content Views', async () => {
112
+ test('Can handle unpublished Content Views', async (done) => {
87
113
  const { results } = cvIndexData;
88
114
  const unpublishedCVs = results.map(cv => ({ ...cv, last_published: null }));
89
115
  const unpublishedCVData = { ...cvIndexData, results: unpublishedCVs };
116
+ const autocompleteScope = mockAutocomplete(nockInstance, autocompleteUrl);
90
117
  const scope = nockInstance
91
118
  .get(cvIndexPath)
92
119
  .query(true)
93
120
  .reply(200, unpublishedCVData);
94
121
 
95
- const { getAllByText } = renderWithApiRedux(<ContentViewsPage />, renderOptions);
122
+ const { getAllByText } = renderWithRedux(<ContentViewsPage />, renderOptions);
123
+
124
+ await patientlyWaitFor(() => expect(getAllByText(/not yet published/i).length).toBeGreaterThan(0));
125
+ assertNockRequest(autocompleteScope);
126
+ assertNockRequest(scope, done);
127
+ });
128
+
129
+ test('Can handle pagination', async (done) => {
130
+ const cvIndexLarge = createBasicCVs(100);
131
+ const { results } = cvIndexLarge;
132
+ const cvIndexFirstPage = { ...cvIndexLarge, ...{ results: results.slice(0, 20) } };
133
+ const cvIndexSecondPage = { ...cvIndexLarge, page: 2, results: results.slice(20, 40) };
134
+ const autocompleteScope = mockAutocomplete(nockInstance, autocompleteUrl);
135
+
136
+ // Match first page API request
137
+ const firstPageScope = nockInstance
138
+ .get(cvIndexPath)
139
+ .query(createContentViewsParams())
140
+ .reply(200, cvIndexFirstPage);
141
+
142
+ // Match second page API request
143
+ const secondPageScope = nockInstance
144
+ .get(cvIndexPath)
145
+ // Using a custom query params matcher because parameters can be strings
146
+ .query(actualQueryObject => parseInt(actualQueryObject.page, 10) === 2)
147
+ .reply(200, cvIndexSecondPage);
148
+
149
+ const { queryByText, getByLabelText } = renderWithRedux(<ContentViewsPage />, renderOptions);
150
+
151
+ // Wait for first paginated page to load and assert only the first page of results are present
152
+ await patientlyWaitFor(() => {
153
+ expect(queryByText(results[0].name)).toBeInTheDocument();
154
+ expect(queryByText(results[19].name)).toBeInTheDocument();
155
+ expect(queryByText(results[21].name)).not.toBeInTheDocument();
156
+ });
157
+
158
+ // Label comes from patternfly, if this test fails, check if patternfly updated the label.
159
+ expect(getByLabelText('Go to next page')).toBeTruthy();
160
+ getByLabelText('Go to next page').click();
161
+
162
+ // Wait for second paginated page to load and assert only the second page of results are present
163
+ await patientlyWaitFor(() => {
164
+ expect(queryByText(results[20].name)).toBeInTheDocument();
165
+ expect(queryByText(results[39].name)).toBeInTheDocument();
166
+ expect(queryByText(results[41].name)).not.toBeInTheDocument();
167
+ });
168
+
169
+ assertNockRequest(autocompleteScope);
170
+ assertNockRequest(firstPageScope);
171
+ assertNockRequest(secondPageScope, done); // Only pass jest callback to the last API request
172
+ });
173
+
174
+ test('Can search for specific Content View', async (done) => {
175
+ const cvname = 'composite one';
176
+ const { results } = cvIndexData;
177
+ const matchQuery = actualParams => actualParams?.search?.includes(cvname);
178
+ const searchResults = {
179
+ ...cvIndexData,
180
+ ...{ total: 1, subtotal: 1, results: results.slice(-1) },
181
+ };
182
+
183
+ const autocompleteScope = mockAutocomplete(nockInstance, autocompleteUrl);
184
+ const withSearchScope = mockAutocomplete(nockInstance, autocompleteUrl, matchQuery);
185
+ const initialScope = nockInstance
186
+ .get(cvIndexPath)
187
+ .query(true)
188
+ .reply(200, cvIndexData);
189
+ const searchResultScope = nockInstance
190
+ .get(cvIndexPath)
191
+ .query(matchQuery)
192
+ .reply(200, searchResults);
193
+
194
+ const {
195
+ getByLabelText,
196
+ getByText,
197
+ queryByText,
198
+ } = renderWithRedux(<ContentViewsPage />, renderOptions);
199
+
200
+ await patientlyWaitFor(() => expect(getByText(firstCV.name)).toBeInTheDocument());
201
+
202
+ const searchInput = getByLabelText(/text input for search/i);
203
+ expect(searchInput).toBeInTheDocument();
204
+ fireEvent.change(searchInput, { target: { value: `name = \"${cvname}\"` } });
205
+
206
+ await patientlyWaitFor(() => {
207
+ expect(getByText(cvname)).toBeInTheDocument();
208
+ expect(queryByText(firstCV.name)).not.toBeInTheDocument();
209
+ });
210
+
211
+ assertNockRequest(autocompleteScope);
212
+ assertNockRequest(initialScope);
213
+ assertNockRequest(withSearchScope);
214
+ assertNockRequest(searchResultScope, done);
215
+ });
216
+
217
+ test('No results message is shown for empty search', async (done) => {
218
+ const cvname = 'notanactualname';
219
+ const query = `name = \"${cvname}\"`;
220
+ const matchQuery = actualParams => actualParams?.search?.includes(cvname);
221
+ const emptyResults = {
222
+ total: 1, subtotal: 1, page: 1, per_page: 20, search: query, results: [],
223
+ };
224
+
225
+ const autocompleteScope = mockAutocomplete(nockInstance, autocompleteUrl);
226
+ const withSearchScope = mockAutocomplete(nockInstance, autocompleteUrl, matchQuery);
227
+ const initialScope = nockInstance
228
+ .get(cvIndexPath)
229
+ .query(true)
230
+ .reply(200, cvIndexData);
231
+ const searchResultScope = nockInstance
232
+ .get(cvIndexPath)
233
+ .query(matchQuery)
234
+ .reply(200, emptyResults);
235
+
236
+ const { getByLabelText, getByText } = renderWithRedux(<ContentViewsPage />, renderOptions);
237
+
238
+ await patientlyWaitFor(() => expect(getByText(firstCV.name)).toBeInTheDocument());
239
+
240
+ fireEvent.change(getByLabelText(/text input for search/i), { target: { value: query } });
241
+
242
+ await patientlyWaitFor(() => expect(getByText(/No matching Content Views found/i)).toBeInTheDocument());
96
243
 
97
- await waitFor(() => expect(getAllByText(/not yet published/i).length).toBeGreaterThan(0));
98
- assertNockRequest(scope);
244
+ assertNockRequest(autocompleteScope);
245
+ assertNockRequest(initialScope);
246
+ assertNockRequest(withSearchScope);
247
+ assertNockRequest(searchResultScope, done);
99
248
  });
249
+ /* eslint-enable no-useless-escape */
@@ -0,0 +1,26 @@
1
+ import React from 'react';
2
+ import PropTypes from 'prop-types';
3
+ import { CubesIcon, CubeIcon } from '@patternfly/react-icons';
4
+ import './contentViewIcon.scss';
5
+
6
+ const ContentViewIcon = ({ composite }) => {
7
+ const props = {
8
+ title: composite ? 'composite' : 'single',
9
+ className: 'svg-icon-centered',
10
+ };
11
+ return (
12
+ <div className="svg-centered-container">
13
+ {composite ? <CubesIcon {...props} /> : <CubeIcon {...props} />}
14
+ </div>
15
+ );
16
+ };
17
+
18
+ ContentViewIcon.propTypes = {
19
+ composite: PropTypes.bool,
20
+ };
21
+
22
+ ContentViewIcon.defaultProps = {
23
+ composite: false,
24
+ };
25
+
26
+ export default ContentViewIcon;
@@ -4,7 +4,7 @@ import {
4
4
  MODULE_STREAM_DETAILS_SUCCESS,
5
5
  MODULE_STREAM_DETAILS_FAILURE,
6
6
  } from './ModuleStreamDetailsConstants';
7
- import { apiError } from '../../../move_to_foreman/common/helpers.js';
7
+ import { apiError } from '../../../utils/helpers.js';
8
8
 
9
9
  export const loadModuleStreamDetails = moduleStreamId => async (dispatch) => {
10
10
  dispatch({ type: MODULE_STREAM_DETAILS_REQUEST });
@@ -3,7 +3,7 @@ import { translate as __ } from 'foremanReact/common/I18n';
3
3
  import {
4
4
  headerFormatter,
5
5
  cellFormatter,
6
- } from '../../../../move_to_foreman/components/common/table';
6
+ } from '../../../../components/pf3Table';
7
7
  import ProfileRpmsCellFormatter from './ProfileRpmsCellFormatter';
8
8
 
9
9
  const TableSchema = [
@@ -1,11 +1,11 @@
1
1
  import { testActionSnapshotWithFixtures } from 'react-redux-test-utils';
2
2
  import api from '../../../../services/api';
3
- import { apiError } from '../../../../move_to_foreman/common/helpers';
3
+ import { apiError } from '../../../../utils/helpers';
4
4
  import { loadModuleStreamDetails } from '../ModuleStreamDetailsActions';
5
5
  import { details } from './moduleStreamDetails.fixtures';
6
6
 
7
7
  jest.mock('../../../../services/api');
8
- jest.mock('../../../../move_to_foreman/common/helpers');
8
+ jest.mock('../../../../utils/helpers');
9
9
 
10
10
  const fixtures = {
11
11
  'should load module stream details on success': () => async (dispatch) => {
@@ -6,7 +6,7 @@ import {
6
6
  MODULE_STREAMS_SUCCESS,
7
7
  MODULE_STREAMS_FAILURE,
8
8
  } from './ModuleStreamsConstants';
9
- import { apiError } from '../../move_to_foreman/common/helpers.js';
9
+ import { apiError } from '../../utils/helpers.js';
10
10
 
11
11
  export const getModuleStreams = (extendedParams = {}) => async (dispatch) => {
12
12
  dispatch({ type: MODULE_STREAMS_REQUEST });
@@ -5,7 +5,7 @@ import { translate as __ } from 'foremanReact/common/I18n';
5
5
  import {
6
6
  headerFormatter,
7
7
  cellFormatter,
8
- } from '../../move_to_foreman/components/common/table';
8
+ } from '../../components/pf3Table';
9
9
 
10
10
 
11
11
  const TableSchema = [
@@ -3,7 +3,7 @@ import { shallow } from 'enzyme';
3
3
  import toJson from 'enzyme-to-json';
4
4
  import ContentTable from '../../../components/Content/ContentTable';
5
5
  import TableSchema from '../../ModuleStreams/ModuleStreamsTableSchema';
6
- import { Table } from '../../../move_to_foreman/components/common/table';
6
+ import { Table } from '../../../components/pf3Table';
7
7
 
8
8
  jest.mock('foremanReact/components/Pagination/PaginationWrapper', () => (<div>Pagination Mock</div>));
9
9
 
@@ -1,4 +1,18 @@
1
1
  export const selectOrganizationState = state => state.katello.organization;
2
2
 
3
+ export const selectManifestName = state =>
4
+ selectOrganizationState(state).owner_details?.upstreamConsumer?.name;
5
+
6
+ // for use in ManageManifestModal to replace getManifestName()
7
+ export const selectManifestHref = state =>
8
+ selectManifestName(state) && [
9
+ 'https://',
10
+ selectOrganizationState(state).owner_details.upstreamConsumer.webUrl,
11
+ selectOrganizationState(state).owner_details.upstreamConsumer.uuid,
12
+ ].join('/');
13
+
14
+ export const selectIsManifestImported = state =>
15
+ !!selectOrganizationState(state).owner_details?.upstreamConsumer?.webUrl;
16
+
3
17
  export const selectSimpleContentAccessEnabled = state =>
4
18
  selectOrganizationState(state).simple_content_access;
@@ -5,7 +5,7 @@ import {
5
5
  PRODUCTS_SUCCESS,
6
6
  PRODUCTS_FAILURE,
7
7
  } from './ProductConstants';
8
- import { apiError } from '../../move_to_foreman/common/helpers.js';
8
+ import { apiError } from '../../utils/helpers.js';
9
9
 
10
10
  export const loadProducts = (params = {}) => async (dispatch) => {
11
11
  dispatch({ type: PRODUCTS_REQUEST });
@@ -9,7 +9,7 @@ import { Grid, Row, Col } from 'react-bootstrap';
9
9
  import { Button } from 'patternfly-react';
10
10
  import { translate as __ } from 'foremanReact/common/I18n';
11
11
  import PermissionDenied from 'foremanReact/components/PermissionDenied';
12
- import { LoadingState } from '../../move_to_pf/LoadingState';
12
+ import { LoadingState } from '../../components/LoadingState';
13
13
  import { createEnabledRepoParams } from '../../redux/actions/RedHatRepositories/enabled';
14
14
  import SearchBar from './components/SearchBar';
15
15
  import RecommendedRepositorySetsToggler from './components/RecommendedRepositorySetsToggler';
@@ -0,0 +1,3 @@
1
+ export const AUTOSEARCH_DELAY = 'autosearch_delay';
2
+ export const AUTOSEARCH_WHILE_TYPING = 'autosearch_while_typing';
3
+ export const CONTENT_DISCONNECTED = 'content_disconnected';
@@ -0,0 +1,33 @@
1
+ import Immutable from 'seamless-immutable';
2
+ import { GET_SETTING_SUCCESS } from 'foremanReact/components/Settings/SettingsConstants';
3
+ import {
4
+ AUTOSEARCH_DELAY,
5
+ AUTOSEARCH_WHILE_TYPING,
6
+ CONTENT_DISCONNECTED,
7
+ } from './SettingsConstants';
8
+
9
+ export const initialSettingsState = Immutable({
10
+ autoSearchEnabled: true,
11
+ autoSearchDelay: 500,
12
+ });
13
+
14
+ export default (state = initialSettingsState, action) => {
15
+ switch (action.type) {
16
+ case GET_SETTING_SUCCESS: {
17
+ const { name, value } = action.response;
18
+ switch (name) {
19
+ case AUTOSEARCH_DELAY:
20
+ return state.set('autoSearchDelay', value);
21
+ case AUTOSEARCH_WHILE_TYPING:
22
+ return state.set('autoSearchEnabled', value);
23
+ case CONTENT_DISCONNECTED:
24
+ return state.set('disconnected', value);
25
+ default:
26
+ return state;
27
+ }
28
+ }
29
+
30
+ default:
31
+ return state;
32
+ }
33
+ };
@@ -0,0 +1,4 @@
1
+ export const selectSettings = state => state.katello.settings.settings;
2
+
3
+ export const selectTableSettings = (state, tableName) =>
4
+ state.katello.settings.tables[tableName] || undefined;