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
@@ -0,0 +1,120 @@
1
+ import React, { useState, useEffect } from 'react';
2
+ import { TextInput, TextArea, Text, TextVariants, Button, Split, SplitItem } from '@patternfly/react-core';
3
+ import { TimesIcon, CheckIcon, PencilAltIcon } from '@patternfly/react-icons';
4
+ import { translate as __ } from 'foremanReact/common/I18n';
5
+ import PropTypes from 'prop-types';
6
+ import Loading from '../Loading';
7
+ import './editableTextInput.scss';
8
+
9
+ const EditableTextInput = ({
10
+ onEdit, value, textArea, attribute,
11
+ }) => {
12
+ // Tracks input box state
13
+ const [inputValue, setInputValue] = useState(value);
14
+ const [editing, setEditing] = useState(false);
15
+ const [submitting, setSubmitting] = useState(false);
16
+
17
+ // Setting didCancel to avoid actions from happening after component has been unmounted
18
+ // see https://overreacted.io/a-complete-guide-to-useeffect/#speaking-of-race-conditions
19
+ useEffect(() => {
20
+ let didCancel = false;
21
+
22
+ const onSubmit = async () => {
23
+ if (submitting) {
24
+ await onEdit(inputValue, attribute);
25
+ if (!didCancel) {
26
+ setSubmitting(false);
27
+ setEditing(false);
28
+ }
29
+ }
30
+ };
31
+ onSubmit();
32
+
33
+ return () => {
34
+ didCancel = true;
35
+ };
36
+ }, [submitting]);
37
+
38
+ // Listen for enter and trigger submit workflow on enter
39
+ useEffect(() => {
40
+ const listener = (event) => {
41
+ if (event.code === 'Enter' || event.code === 'NumpadEnter') {
42
+ if (editing) setSubmitting(true);
43
+ }
44
+ };
45
+ document.addEventListener('keydown', listener);
46
+ return () => {
47
+ document.removeEventListener('keydown', listener);
48
+ };
49
+ }, [editing]);
50
+
51
+ const onClear = () => {
52
+ setInputValue(value);
53
+ setEditing(false);
54
+ };
55
+
56
+ const inputProps = {
57
+ value: inputValue || '',
58
+ onChange: v => setInputValue(v),
59
+ };
60
+
61
+ if (submitting) return <Loading size="sm" />;
62
+ if (editing) {
63
+ return (
64
+ <Split>
65
+ <SplitItem>
66
+ {textArea ?
67
+ (<TextArea {...inputProps} aria-label={`${attribute} text area`} />) :
68
+ (<TextInput {...inputProps} type="text" aria-label={`${attribute} text input`} />)}
69
+ </SplitItem>
70
+ <SplitItem>
71
+ <Button
72
+ aria-label={`submit ${attribute}`}
73
+ variant="plain"
74
+ onClick={() => setSubmitting(true)}
75
+ >
76
+ <CheckIcon />
77
+ </Button>
78
+ </SplitItem>
79
+ <SplitItem>
80
+ <Button aria-label={`clear ${attribute}`} variant="plain" onClick={onClear}>
81
+ <TimesIcon />
82
+ </Button>
83
+ </SplitItem>
84
+ </Split>
85
+ );
86
+ }
87
+ return (
88
+ <Split>
89
+ <SplitItem>
90
+ <Text aria-label={`${attribute} text value`} component={TextVariants.p}>
91
+ {value || (<i>{__('None provided')}</i>)}
92
+ </Text>
93
+ </SplitItem>
94
+ <SplitItem>
95
+ <Button
96
+ className="foreman-edit-icon"
97
+ aria-label={`edit ${attribute}`}
98
+ variant="plain"
99
+ onClick={() => setEditing(true)}
100
+ >
101
+ <PencilAltIcon />
102
+ </Button>
103
+ </SplitItem>
104
+ </Split>
105
+ );
106
+ };
107
+
108
+ EditableTextInput.propTypes = {
109
+ onEdit: PropTypes.func.isRequired,
110
+ value: PropTypes.string,
111
+ attribute: PropTypes.string.isRequired,
112
+ textArea: PropTypes.bool, // Is a text area instead of input when editing
113
+ };
114
+
115
+ EditableTextInput.defaultProps = {
116
+ textArea: false,
117
+ value: '', // API can return null, so default to empty string
118
+ };
119
+
120
+ export default EditableTextInput;
@@ -0,0 +1,52 @@
1
+ import React from 'react';
2
+ import { render, patientlyWaitFor, fireEvent } from 'react-testing-lib-wrapper';
3
+ import EditableTextInput from '../EditableTextInput';
4
+
5
+ const actualValue = 'burger';
6
+ const attribute = 'favorite_food';
7
+ const defaultProps = {
8
+ onEdit: jest.fn(),
9
+ value: actualValue,
10
+ attribute,
11
+ };
12
+
13
+ test('Passed function is called after editing and clicking submit', async () => {
14
+ const mockEdit = jest.fn();
15
+ const { getByLabelText } = render(<EditableTextInput {...defaultProps} onEdit={mockEdit} />);
16
+
17
+ getByLabelText(`edit ${attribute}`).click();
18
+ fireEvent.change(getByLabelText(`${attribute} text input`), { target: { value: actualValue } });
19
+ getByLabelText(`submit ${attribute}`).click();
20
+
21
+ await patientlyWaitFor(() => expect(mockEdit.mock.calls).toHaveLength(1));
22
+ expect(mockEdit.mock.calls[0][0]).toBe(actualValue); // first arg
23
+ });
24
+
25
+ test('Passed function is called after editing and hitting enter', async () => {
26
+ const mockEdit = jest.fn();
27
+ const { getByLabelText } = render(<EditableTextInput {...defaultProps} onEdit={mockEdit} />);
28
+
29
+ getByLabelText(`edit ${attribute}`).click();
30
+ const textInputLabel = `${attribute} text input`;
31
+ fireEvent.change(getByLabelText(textInputLabel), { target: { value: actualValue } });
32
+ fireEvent.keyDown(getByLabelText(textInputLabel), { key: 'Enter', code: 'Enter' });
33
+
34
+ await patientlyWaitFor(() => expect(mockEdit.mock.calls).toHaveLength(1));
35
+ expect(mockEdit.mock.calls[0][0]).toBe(actualValue); // first arg
36
+ });
37
+
38
+ test('input is set back to original value after clearing', () => {
39
+ const value = 'Sandwich';
40
+ const { getByLabelText } = render(<EditableTextInput {...defaultProps} />);
41
+
42
+ // Show original value on load
43
+ expect(getByLabelText(`${attribute} text value`)).toHaveTextContent(actualValue);
44
+ getByLabelText(`edit ${attribute}`).click();
45
+ // Update text input
46
+ fireEvent.change(getByLabelText(`${attribute} text input`), { target: { value } });
47
+ expect(getByLabelText(`${attribute} text input`)).toHaveValue(value);
48
+ // Clear text
49
+ getByLabelText(`clear ${attribute}`).click();
50
+ // Original value is still showing even though it's been edited
51
+ expect(getByLabelText(`${attribute} text value`)).toHaveTextContent(actualValue);
52
+ });
@@ -0,0 +1,14 @@
1
+ .foreman-limited-text {
2
+ max-width: 200px;
3
+ margin: auto 0px;
4
+ }
5
+
6
+ .foreman-limited-editable-text {
7
+ max-width: 300px;
8
+ margin: auto 0px;
9
+ }
10
+
11
+ // Edit icon isn't in line with text
12
+ .foreman-edit-icon {
13
+ padding-top: 2px;
14
+ }
@@ -0,0 +1,3 @@
1
+ import EditableTextInput from './EditableTextInput';
2
+
3
+ export default EditableTextInput;
@@ -8,23 +8,26 @@ import {
8
8
  Spinner,
9
9
  } from '@patternfly/react-core';
10
10
 
11
- const Loading = ({ size }) => (
11
+ const Loading = ({ size, showText }) => (
12
12
  <Bullseye>
13
13
  <EmptyState>
14
- <EmptyStateIcon variant="container" component={Spinner} />
15
- <Title size={size}>
16
- Loading
17
- </Title>
14
+ <EmptyStateIcon size={size} variant="container" component={Spinner} />
15
+ {showText && (
16
+ <Title size={size} headingLevel="h4">
17
+ Loading
18
+ </Title>)}
18
19
  </EmptyState>
19
20
  </Bullseye>
20
21
  );
21
22
 
22
23
  Loading.propTypes = {
23
24
  size: PropTypes.string,
25
+ showText: PropTypes.bool,
24
26
  };
25
27
 
26
28
  Loading.defaultProps = {
27
29
  size: 'lg',
30
+ showText: true,
28
31
  };
29
32
 
30
33
 
@@ -2,7 +2,7 @@ import React from 'react';
2
2
  import PropTypes from 'prop-types';
3
3
  import { translate as __ } from 'foremanReact/common/I18n';
4
4
  import { FormGroup, ControlLabel } from 'react-bootstrap';
5
- import BootstrapSelect from '../../move_to_pf/react-bootstrap-select';
5
+ import BootstrapSelect from '../../components/react-bootstrap-select';
6
6
 
7
7
  function MultiSelect(props) {
8
8
  const {
@@ -0,0 +1,124 @@
1
+ /* eslint-disable import/no-extraneous-dependencies */
2
+ import React, { Component } from 'react';
3
+ import { ControlLabel } from 'react-bootstrap';
4
+ import PropTypes from 'prop-types';
5
+ import { translate as __ } from 'foremanReact/common/I18n';
6
+ import TypeAhead from '../TypeAhead';
7
+ import api from '../../services/api';
8
+ import { stringIncludes } from './helpers';
9
+ import {
10
+ AUTOSEARCH_DELAY,
11
+ AUTOSEARCH_WHILE_TYPING,
12
+ } from '../../scenes/Settings/SettingsConstants';
13
+
14
+ class Search extends Component {
15
+ constructor(props) {
16
+ super(props);
17
+ this.state = { items: [], typingTimeout: 0 };
18
+ }
19
+
20
+ componentDidMount() {
21
+ this.onInputUpdate();
22
+ this.props.loadSetting(AUTOSEARCH_DELAY);
23
+ this.props.loadSetting(AUTOSEARCH_WHILE_TYPING);
24
+ }
25
+
26
+ onInputUpdate = async (searchTerm = '') => {
27
+ const { getAutoCompleteParams, settings: { autoSearchEnabled }, patternfly4 } = this.props;
28
+ const items = this.state.items.filter(({ text }) => stringIncludes(text, searchTerm));
29
+
30
+ if (items.length !== this.state.items.length) {
31
+ this.setState({ items });
32
+ }
33
+
34
+ const params = getAutoCompleteParams(searchTerm);
35
+ const autoCompleteParams = [
36
+ params.endpoint,
37
+ params.headers || {},
38
+ params.params || {},
39
+ ];
40
+
41
+ if (autoCompleteParams[0] !== '') {
42
+ const { data } = await api.get(...autoCompleteParams);
43
+ this.setState({
44
+ items: data.filter(({ error }) => !error).map(({ label }) => ({
45
+ text: label.trim(),
46
+ })),
47
+ });
48
+ }
49
+
50
+ if (autoSearchEnabled && patternfly4 && searchTerm.length > 0) {
51
+ this.autoSearch(searchTerm);
52
+ }
53
+ };
54
+
55
+ onSearch = (search) => {
56
+ if (this.props.updateSearchQuery) this.props.updateSearchQuery(search);
57
+ this.props.onSearch(search);
58
+ };
59
+
60
+ // Continually clear and set the timeout as the user types. When the typing pauses, perform the
61
+ // search. This allows us to not overload the server by requesting on each keystroke.
62
+ autoSearch(searchTerm) {
63
+ const { settings: { autoSearchDelay } } = this.props;
64
+ if (this.state.typingTimeout) clearTimeout(this.state.typingTimeout);
65
+
66
+ this.setState({
67
+ typingTimeout: setTimeout(() => this.props.onSearch(searchTerm), autoSearchDelay),
68
+ });
69
+ }
70
+
71
+ render() {
72
+ const { initialInputValue, patternfly4, settings: { autoSearchEnabled } } = this.props;
73
+ return (
74
+ <div>
75
+ <ControlLabel srOnly>{__('Search')}</ControlLabel>
76
+ <TypeAhead
77
+ items={this.state.items}
78
+ onInputUpdate={this.onInputUpdate}
79
+ onSearch={this.onSearch}
80
+ initialInputValue={initialInputValue}
81
+ patternfly4={patternfly4}
82
+ autoSearchEnabled={autoSearchEnabled}
83
+ />
84
+ </div>
85
+ );
86
+ }
87
+ }
88
+
89
+ Search.propTypes = {
90
+ /** Callback function when the "Search" button is pressed:
91
+ onSearch(searchQuery)
92
+ */
93
+ onSearch: PropTypes.func.isRequired,
94
+ /** Function returning params for the scoped-search complete api call:
95
+ getAutoCompleteParams(searchQuery)
96
+
97
+ Should return a shape { headers, params, endpoint }, e.g.:
98
+ {
99
+ headers: {},
100
+ params: { organization_id, search },
101
+ endpoint: '/subscriptions/auto_complete_search'
102
+ }
103
+ */
104
+ getAutoCompleteParams: PropTypes.func.isRequired,
105
+ loadSetting: PropTypes.func.isRequired,
106
+ updateSearchQuery: PropTypes.func,
107
+ initialInputValue: PropTypes.string,
108
+ patternfly4: PropTypes.bool,
109
+ settings: PropTypes.shape({
110
+ autoSearchEnabled: PropTypes.bool,
111
+ autoSearchDelay: PropTypes.number,
112
+ }),
113
+ };
114
+
115
+ Search.defaultProps = {
116
+ updateSearchQuery: undefined,
117
+ initialInputValue: '',
118
+ patternfly4: false,
119
+ settings: {
120
+ autoSearchEnabled: true,
121
+ },
122
+ };
123
+
124
+ export default Search;
@@ -3,12 +3,13 @@ import { shallow } from 'enzyme';
3
3
  import toJson from 'enzyme-to-json';
4
4
  import { mock as mockApi } from '../../mockRequest';
5
5
 
6
- import Search from '../Search';
6
+ import Search from '../Search/Search';
7
7
 
8
8
  describe('Search component', () => {
9
9
  const getBaseProps = () => ({
10
10
  onSearch: () => {},
11
11
  getAutoCompleteParams: () => ({ endpoint: '/fake' }),
12
+ loadSetting: jest.fn(),
12
13
  });
13
14
 
14
15
  describe('rendering', () => {
@@ -10,10 +10,12 @@ exports[`Search component rendering renders correctly 1`] = `
10
10
  </ControlLabel>
11
11
  <TypeAhead
12
12
  actionText="Search"
13
+ autoSearchEnabled={true}
13
14
  initialInputValue=""
14
15
  items={Array []}
15
16
  onInputUpdate={[Function]}
16
17
  onSearch={[Function]}
18
+ patternfly4={false}
17
19
  />
18
20
  </div>
19
21
  `;
@@ -0,0 +1,124 @@
1
+ import React from 'react';
2
+ import { renderWithRedux, patientlyWaitFor, fireEvent } from 'react-testing-lib-wrapper';
3
+ import nock, {
4
+ nockInstance, assertNockRequest, mockAutocomplete, mockSetting,
5
+ } from '../../../test-utils/nockWrapper';
6
+ import { AUTOSEARCH_WHILE_TYPING, AUTOSEARCH_DELAY } from '../../../scenes/Settings/SettingsConstants.js';
7
+ import Search from '../../Search';
8
+
9
+ const endpoint = '/fake_endpoint';
10
+ const searchButtonLabel = 'search button';
11
+ const props = {
12
+ onSearch: jest.fn(),
13
+ getAutoCompleteParams: search => ({
14
+ params: { organization_id: 1, search },
15
+ endpoint,
16
+ }),
17
+ patternfly4: true,
18
+ };
19
+
20
+ let searchDelayScope;
21
+ beforeEach(() => {
22
+ searchDelayScope = mockSetting(nockInstance, AUTOSEARCH_DELAY, 500);
23
+ });
24
+
25
+ afterEach(() => {
26
+ assertNockRequest(searchDelayScope);
27
+ nock.cleanAll();
28
+ });
29
+
30
+ test('Autocomplete shows on input', async (done) => {
31
+ const suggestion = 'suggestedQuery';
32
+ const response = [
33
+ {
34
+ completed: '', part: ` ${suggestion} `, label: ` ${suggestion} `, category: '',
35
+ },
36
+ ];
37
+ const query = { organization_id: 1, search: 'foo' };
38
+ const autoSearchScope = mockSetting(nockInstance, AUTOSEARCH_WHILE_TYPING, true);
39
+ const initialScope = mockAutocomplete(nockInstance, endpoint, { ...query, search: '' }, []);
40
+ const autocompleteScope = mockAutocomplete(nockInstance, endpoint, query, response);
41
+
42
+ const { getByLabelText, getByText, queryByText } = renderWithRedux(<Search {...props} />);
43
+
44
+ expect(queryByText(`${suggestion}`)).not.toBeInTheDocument();
45
+
46
+ fireEvent.change(getByLabelText(/text input for search/i), { target: { value: 'foo' } });
47
+
48
+ await patientlyWaitFor(() => expect(getByText(`${suggestion}`)).toBeInTheDocument());
49
+
50
+ assertNockRequest(initialScope);
51
+ assertNockRequest(autoSearchScope);
52
+ assertNockRequest(autocompleteScope, done);
53
+ });
54
+
55
+ test('autosearch turned on does not show patternfly 4 search button', async (done) => {
56
+ const autoSearchScope = mockSetting(nockInstance, AUTOSEARCH_WHILE_TYPING, true);
57
+ const autocompleteScope = mockAutocomplete(nockInstance, endpoint);
58
+
59
+ const { queryByLabelText } = renderWithRedux(<Search {...props} />);
60
+
61
+ await patientlyWaitFor(() => expect(queryByLabelText(searchButtonLabel)).not.toBeInTheDocument());
62
+
63
+ assertNockRequest(autocompleteScope);
64
+ assertNockRequest(autoSearchScope, done);
65
+ });
66
+
67
+ test('autosearch turned off does show patternfly 4 search button', async (done) => {
68
+ const autoSearchScope = mockSetting(nockInstance, AUTOSEARCH_WHILE_TYPING, false);
69
+ const autocompleteScope = mockAutocomplete(nockInstance, endpoint);
70
+
71
+ const { getByLabelText } = renderWithRedux(<Search {...props} />);
72
+
73
+ // Using patientlyWaitFor as the autoSearch setting defaults to true,
74
+ // it won't be changed until http call
75
+ await patientlyWaitFor(() => expect(getByLabelText(searchButtonLabel)).toBeInTheDocument());
76
+
77
+ assertNockRequest(autoSearchScope);
78
+ assertNockRequest(autocompleteScope, done);
79
+ });
80
+
81
+ test('autosearch turned on does not affect patternfly 3 buttons', async (done) => {
82
+ const autoSearchScope = mockSetting(nockInstance, AUTOSEARCH_WHILE_TYPING, true);
83
+ const autocompleteScope = mockAutocomplete(nockInstance, endpoint);
84
+
85
+ const { getByLabelText } = renderWithRedux(<Search {...{ ...props, patternfly4: false }} />);
86
+
87
+ await patientlyWaitFor(() => expect(getByLabelText('patternfly 3 search button')).toBeInTheDocument());
88
+
89
+ assertNockRequest(autoSearchScope);
90
+ assertNockRequest(autocompleteScope, done);
91
+ });
92
+
93
+ test('search function is called when search is typed into with autosearch', async (done) => {
94
+ const autoSearchScope = mockSetting(nockInstance, AUTOSEARCH_WHILE_TYPING, true);
95
+ const autocompleteScope = mockAutocomplete(nockInstance, endpoint, true, [], 2);
96
+ const mockSearch = jest.fn();
97
+
98
+ const { getByLabelText } = renderWithRedux(<Search {...{ ...props, onSearch: mockSearch }} />);
99
+ fireEvent.change(getByLabelText(/text input for search/i), { target: { value: 'foo' } });
100
+ await patientlyWaitFor(() => expect(mockSearch.mock.calls).toHaveLength(1));
101
+
102
+ assertNockRequest(autoSearchScope);
103
+ assertNockRequest(autocompleteScope, done);
104
+ });
105
+
106
+ test('search function is called by clicking search button without autosearch', async (done) => {
107
+ const autoSearchScope = mockSetting(nockInstance, AUTOSEARCH_WHILE_TYPING, false);
108
+ const autocompleteScope = mockAutocomplete(nockInstance, endpoint, true, [], 2);
109
+ const mockSearch = jest.fn();
110
+
111
+ const { getByLabelText } = renderWithRedux(<Search {...{ ...props, onSearch: mockSearch }} />);
112
+
113
+ fireEvent.change(getByLabelText(/text input for search/i), { target: { value: 'foo' } });
114
+ let searchButton;
115
+ await patientlyWaitFor(() => {
116
+ searchButton = getByLabelText(searchButtonLabel);
117
+ expect(searchButton).toBeInTheDocument();
118
+ });
119
+ searchButton.click();
120
+ expect(mockSearch.mock.calls).toHaveLength(1);
121
+
122
+ assertNockRequest(autoSearchScope);
123
+ assertNockRequest(autocompleteScope, done);
124
+ });
@@ -1,91 +1,15 @@
1
- /* eslint-disable import/no-extraneous-dependencies */
2
- import React, { Component } from 'react';
3
- import { ControlLabel } from 'react-bootstrap';
4
- import PropTypes from 'prop-types';
5
- import { translate as __ } from 'foremanReact/common/I18n';
6
- import TypeAhead from '../../move_to_pf/TypeAhead/TypeAhead';
7
- import api from '../../services/api';
8
- import { stringIncludes } from './helpers';
1
+ import { bindActionCreators } from 'redux';
2
+ import { connect } from 'react-redux';
3
+ import * as settingActions from 'foremanReact/components/Settings/SettingsActions';
4
+ import { selectSettings } from '../../scenes/Settings/SettingsSelectors';
5
+ import Search from './Search';
9
6
 
10
- class Search extends Component {
11
- constructor(props) {
12
- super(props);
13
- this.state = { items: [] };
14
- this.onInputUpdate = this.onInputUpdate.bind(this);
15
- this.onSearch = this.onSearch.bind(this);
16
- }
7
+ const mapStateToProps = state => ({
8
+ settings: selectSettings(state),
9
+ });
17
10
 
18
- componentDidMount() {
19
- this.onInputUpdate();
20
- }
11
+ const actions = { ...settingActions };
21
12
 
22
- async onInputUpdate(searchTerm = '') {
23
- const items = this.state.items.filter(({ text }) => stringIncludes(text, searchTerm));
13
+ const mapDispatchToProps = dispatch => bindActionCreators(actions, dispatch);
24
14
 
25
- if (items.length !== this.state.items.length) {
26
- this.setState({ items });
27
- }
28
-
29
- const params = this.props.getAutoCompleteParams(searchTerm);
30
- const autoCompleteParams = [
31
- params.endpoint,
32
- params.headers || {},
33
- params.params || {},
34
- ];
35
-
36
- if (autoCompleteParams[0] !== '') {
37
- const { data } = await api.get(...autoCompleteParams);
38
- this.setState({
39
- items: data.filter(({ error }) => !error).map(({ label }) => ({
40
- text: label.trim(),
41
- })),
42
- });
43
- }
44
- }
45
-
46
- onSearch(search) {
47
- if (this.props.updateSearchQuery) this.props.updateSearchQuery(search);
48
- this.props.onSearch(search);
49
- }
50
-
51
- render() {
52
- const { initialInputValue } = this.props;
53
- return (
54
- <div>
55
- <ControlLabel srOnly>{__('Search')}</ControlLabel>
56
- <TypeAhead
57
- items={this.state.items}
58
- onInputUpdate={this.onInputUpdate}
59
- onSearch={this.onSearch}
60
- initialInputValue={initialInputValue}
61
- />
62
- </div>
63
- );
64
- }
65
- }
66
-
67
- Search.propTypes = {
68
- /** Callback function when the "Search" button is pressed:
69
- onSearch(searchQuery)
70
- */
71
- onSearch: PropTypes.func.isRequired,
72
- /** Function returning params for the scoped-search complete api call:
73
- getAutoCompleteParams(searchQuery)
74
-
75
- Should return a shape { headers, params, endpoint }, e.g.:
76
- {
77
- headers: {},
78
- params: { organization_id, search },
79
- endpoint: '/subscriptions/auto_complete_search'
80
- }
81
- */
82
- getAutoCompleteParams: PropTypes.func.isRequired,
83
- updateSearchQuery: PropTypes.func,
84
- initialInputValue: PropTypes.string,
85
- };
86
-
87
- Search.defaultProps = {
88
- updateSearchQuery: undefined,
89
- initialInputValue: '',
90
- };
91
- export default Search;
15
+ export default connect(mapStateToProps, mapDispatchToProps)(Search);
File without changes
@@ -5,10 +5,10 @@ import { Form, Button } from 'patternfly-react';
5
5
  import { withRouter } from 'react-router-dom';
6
6
  import { bindActionCreators } from 'redux';
7
7
  import { connect } from 'react-redux';
8
- import Select from '../../move_to_pf/Select/Select';
8
+ import Select from '../../components/Select/Select';
9
9
  import * as SelectOrgActions from './SelectOrgAction';
10
10
  import reducer from './SelectOrgReducer';
11
- import { LoadingState } from '../../move_to_pf/LoadingState';
11
+ import { LoadingState } from '../../components/LoadingState';
12
12
  import './SelectOrg.scss';
13
13
 
14
14
  class SetOrganization extends Component {