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,26 @@
1
+ import React from 'react';
2
+ import PropTypes from 'prop-types';
3
+ import { Tab, TabTitleText } from '@patternfly/react-core';
4
+ import './TabWrapper.scss';
5
+
6
+ // Wrapper for patternfly 4 tabs for styling and consistency purposes
7
+ const TabWrapper = ({ children, title, index }) => (
8
+ <Tab
9
+ aria-label={`${title} tab`}
10
+ key={`${title}`}
11
+ eventKey={index}
12
+ title={<TabTitleText>{title}</TabTitleText>}
13
+ >
14
+ <div className="tab-body-with-spacing">
15
+ {children}
16
+ </div>
17
+ </Tab>
18
+ );
19
+
20
+ TabWrapper.propTypes = {
21
+ children: PropTypes.element.isRequired,
22
+ title: PropTypes.string.isRequired,
23
+ index: PropTypes.number.isRequired,
24
+ };
25
+
26
+ export default TabWrapper;
@@ -0,0 +1,3 @@
1
+ import TabbedView from './TabbedView';
2
+
3
+ export default TabbedView;
@@ -0,0 +1,38 @@
1
+ import React, { useState } from 'react';
2
+ import PropTypes from 'prop-types';
3
+ import { Tabs, Tab, TabTitleText } from '@patternfly/react-core';
4
+ import './TabbedView.scss';
5
+
6
+ const TabbedView = ({ tabs }) => {
7
+ const [activeTabKey, setActiveTabKey] = useState(0);
8
+ const handleTabClick = (_event, tabIndex) => setActiveTabKey(tabIndex);
9
+
10
+ return (
11
+ <Tabs activeKey={activeTabKey} onSelect={handleTabClick}>
12
+ {tabs.map((tab, i) => {
13
+ const { title, content } = tab;
14
+ return (
15
+ <Tab
16
+ aria-label={`${title} tab`}
17
+ key={`${title}`}
18
+ eventKey={i}
19
+ title={<TabTitleText>{title}</TabTitleText>}
20
+ >
21
+ <div className="tab-body-with-spacing">
22
+ {content}
23
+ </div>
24
+ </Tab>
25
+ );
26
+ })}
27
+ </Tabs>
28
+ );
29
+ };
30
+
31
+ TabbedView.propTypes = {
32
+ tabs: PropTypes.arrayOf(PropTypes.shape({
33
+ title: PropTypes.string,
34
+ content: PropTypes.element,
35
+ })).isRequired,
36
+ };
37
+
38
+ export default TabbedView;
@@ -0,0 +1,3 @@
1
+ .tab-body-with-spacing {
2
+ margin: 24px 0px;
3
+ }
@@ -0,0 +1,3 @@
1
+ import TabbedView from './TabbedView';
2
+
3
+ export default TabbedView;
@@ -0,0 +1,61 @@
1
+ import React from 'react';
2
+ import { EmptyState,
3
+ EmptyStateBody,
4
+ EmptyStateIcon,
5
+ EmptyStateVariant,
6
+ Bullseye,
7
+ Title } from '@patternfly/react-core';
8
+ import PropTypes from 'prop-types';
9
+ import { CubeIcon, ExclamationCircleIcon, SearchIcon } from '@patternfly/react-icons';
10
+ import { global_danger_color_200 as dangerColor } from '@patternfly/react-tokens';
11
+
12
+ const KatelloEmptyStateIcon = ({ error, search }) => {
13
+ if (error) return <EmptyStateIcon icon={ExclamationCircleIcon} color={dangerColor.value} />;
14
+ if (search) return <EmptyStateIcon icon={SearchIcon} />;
15
+ return <EmptyStateIcon icon={CubeIcon} />;
16
+ };
17
+
18
+ const EmptyStateMessage = ({
19
+ title, body, error, search,
20
+ }) => (
21
+ <Bullseye>
22
+ <EmptyState variant={EmptyStateVariant.small}>
23
+ <KatelloEmptyStateIcon error={!!error} search={search} />
24
+ <Title headingLevel="h2" size="lg">
25
+ {title}
26
+ </Title>
27
+ <EmptyStateBody>
28
+ {body}
29
+ </EmptyStateBody>
30
+ </EmptyState>
31
+ </Bullseye>
32
+ );
33
+
34
+ KatelloEmptyStateIcon.propTypes = {
35
+ error: PropTypes.bool,
36
+ search: PropTypes.bool,
37
+ };
38
+
39
+ KatelloEmptyStateIcon.defaultProps = {
40
+ error: false,
41
+ search: false,
42
+ };
43
+
44
+ EmptyStateMessage.propTypes = {
45
+ title: PropTypes.string,
46
+ body: PropTypes.string,
47
+ error: PropTypes.oneOfType([
48
+ PropTypes.shape({}),
49
+ PropTypes.string,
50
+ ]),
51
+ search: PropTypes.bool,
52
+ };
53
+
54
+ EmptyStateMessage.defaultProps = {
55
+ title: 'Unable to connect',
56
+ body: 'There was an error retrieving data from the server. Check your connection and try again.',
57
+ error: undefined,
58
+ search: false,
59
+ };
60
+
61
+ export default EmptyStateMessage;
@@ -4,21 +4,28 @@ import {
4
4
  TableHeader,
5
5
  TableBody,
6
6
  } from '@patternfly/react-table';
7
- import PropTypes from 'prop-types';
8
7
  import { STATUS } from 'foremanReact/constants';
8
+ import PropTypes from 'prop-types';
9
9
 
10
- import EmptyStateMessage from '../components/EmptyStateMessage';
11
- import Loading from '../components/Loading';
10
+ import EmptyStateMessage from './EmptyStateMessage';
11
+ import Loading from '../../components/Loading';
12
12
 
13
- const TableWrapper = ({
14
- status, cells, rows, error, emptyTitle, emptyBody, ...extraTableProps
13
+ const MainTable = ({
14
+ status, cells, rows, error, emptyContentTitle, emptyContentBody,
15
+ emptySearchTitle, emptySearchBody, searchIsActive, ...extraTableProps
15
16
  }) => {
16
17
  if (status === STATUS.PENDING) return (<Loading />);
17
18
  // Can we display the error message?
18
19
  if (status === STATUS.ERROR) return (<EmptyStateMessage error={error} />);
19
- // Can we prevent flash of empty row message while rows are loading with data?
20
+ if (status === STATUS.RESOLVED && searchIsActive && rows.length === 0) {
21
+ return (<EmptyStateMessage
22
+ title={emptySearchTitle}
23
+ body={emptySearchBody}
24
+ search
25
+ />);
26
+ }
20
27
  if (status === STATUS.RESOLVED && rows.length === 0) {
21
- return (<EmptyStateMessage title={emptyTitle} body={emptyBody} />);
28
+ return (<EmptyStateMessage title={emptyContentTitle} body={emptyContentBody} />);
22
29
  }
23
30
 
24
31
  const tableProps = { cells, rows, ...extraTableProps };
@@ -34,7 +41,7 @@ const TableWrapper = ({
34
41
  );
35
42
  };
36
43
 
37
- TableWrapper.propTypes = {
44
+ MainTable.propTypes = {
38
45
  status: PropTypes.string.isRequired,
39
46
  cells: PropTypes.arrayOf(PropTypes.oneOfType([
40
47
  PropTypes.shape({}),
@@ -44,12 +51,16 @@ TableWrapper.propTypes = {
44
51
  PropTypes.shape({}),
45
52
  PropTypes.string,
46
53
  ]),
47
- emptyBody: PropTypes.string.isRequired,
48
- emptyTitle: PropTypes.string.isRequired,
54
+ emptyContentTitle: PropTypes.string.isRequired,
55
+ emptyContentBody: PropTypes.string.isRequired,
56
+ emptySearchTitle: PropTypes.string.isRequired,
57
+ emptySearchBody: PropTypes.string.isRequired,
58
+ searchIsActive: PropTypes.bool,
49
59
  };
50
60
 
51
- TableWrapper.defaultProps = {
61
+ MainTable.defaultProps = {
52
62
  error: null,
63
+ searchIsActive: false,
53
64
  };
54
65
 
55
- export default TableWrapper;
66
+ export default MainTable;
@@ -0,0 +1,94 @@
1
+ import React, { useEffect, useState } from 'react';
2
+ import { Pagination, Flex, FlexItem } from '@patternfly/react-core';
3
+
4
+ import PropTypes from 'prop-types';
5
+ import { useDispatch } from 'react-redux';
6
+ import { usePaginationOptions, useForemanSettings } from 'foremanReact/Root/Context/ForemanContext';
7
+
8
+ import MainTable from './MainTable';
9
+ import Search from '../../components/Search';
10
+ import { orgId } from '../../services/api';
11
+
12
+ /* Patternfly 4 table wrapper */
13
+ const TableWrapper = ({
14
+ metadata, fetchItems, autocompleteEndpoint, ...allTableProps
15
+ }) => {
16
+ const { search: currentSearch } = metadata;
17
+ const dispatch = useDispatch();
18
+ const { foremanPerPage = 20 } = useForemanSettings();
19
+ // setting pagination to local state so it doesn't disappear when page reloads
20
+ const [perPage, setPerPage] = useState(foremanPerPage);
21
+ const [page, setPage] = useState(1);
22
+ const [total, setTotal] = useState(0);
23
+
24
+ const updatePagination = (data) => {
25
+ const { total: newTotal, page: newPage, per_page: newPerPage } = data;
26
+ if (newTotal) setTotal(parseInt(newTotal, 10));
27
+ if (newPage) setPage(parseInt(newPage, 10));
28
+ if (newPerPage) setPerPage(parseInt(newPerPage, 10));
29
+ };
30
+
31
+ useEffect(() => updatePagination(metadata), [metadata]);
32
+
33
+ const paginationParams = () => ({ per_page: perPage, page });
34
+
35
+ const getAutoCompleteParams = search => ({
36
+ endpoint: autocompleteEndpoint,
37
+ params: {
38
+ organization_id: orgId(),
39
+ search,
40
+ },
41
+ });
42
+
43
+ const onSearch = search => dispatch(fetchItems({ ...paginationParams(), search }));
44
+
45
+ const onPaginationUpdate = (updatedPagination) => {
46
+ updatePagination(updatedPagination);
47
+ dispatch(fetchItems({ ...paginationParams(), ...updatedPagination, search: currentSearch }));
48
+ };
49
+
50
+ return (
51
+ <React.Fragment>
52
+ <Flex>
53
+ <FlexItem>
54
+ <Search patternfly4 {...{ onSearch, getAutoCompleteParams }} />
55
+ </FlexItem>
56
+ <FlexItem align={{ default: 'alignRight' }}>
57
+ <Pagination
58
+ itemCount={total}
59
+ page={page}
60
+ perPage={perPage}
61
+ onSetPage={(_evt, updated) => onPaginationUpdate({ page: updated })}
62
+ onPerPageSelect={(_evt, updated) => onPaginationUpdate({ per_page: updated })}
63
+ perPageOptions={usePaginationOptions().map(p => ({ title: p.toString(), value: p }))}
64
+ variant="top"
65
+ />
66
+ </FlexItem>
67
+ </Flex>
68
+ <MainTable searchIsActive={!!currentSearch} {...allTableProps} />
69
+ </React.Fragment>
70
+ );
71
+ };
72
+
73
+ TableWrapper.propTypes = {
74
+ fetchItems: PropTypes.func.isRequired,
75
+ metadata: PropTypes.shape({
76
+ total: PropTypes.number,
77
+ page: PropTypes.oneOfType([
78
+ PropTypes.number,
79
+ PropTypes.string, // The API can sometimes return strings
80
+ ]),
81
+ per_page: PropTypes.oneOfType([
82
+ PropTypes.number,
83
+ PropTypes.string,
84
+ ]),
85
+ search: PropTypes.string,
86
+ }),
87
+ autocompleteEndpoint: PropTypes.string.isRequired,
88
+ };
89
+
90
+ TableWrapper.defaultProps = {
91
+ metadata: {},
92
+ };
93
+
94
+ export default TableWrapper;
@@ -0,0 +1,109 @@
1
+ import React, { Component } from 'react';
2
+ import Downshift from 'downshift';
3
+ import PropTypes from 'prop-types';
4
+
5
+ import TypeAheadSearch from './pf3Search/TypeAheadSearch';
6
+ // eslint-disable-next-line import/no-named-default
7
+ import { default as TypeAheadSearchPf4 } from './pf4Search/TypeAheadSearch';
8
+ import { getActiveItems } from './helpers/helpers';
9
+
10
+ import './TypeAhead.scss';
11
+
12
+ class TypeAhead extends Component {
13
+ constructor(props) {
14
+ super(props);
15
+
16
+ this.state = {
17
+ inputValue: this.props.initialInputValue,
18
+ };
19
+ }
20
+
21
+ handleStateChange = ({ inputValue }) => {
22
+ if (typeof inputValue === 'string') {
23
+ this.props.onInputUpdate(inputValue);
24
+ this.setState({ inputValue });
25
+ }
26
+ };
27
+
28
+ clearSearch = () => {
29
+ this.setState({ inputValue: '' }, () => this.props.onSearch(this.state.inputValue));
30
+ };
31
+
32
+ render() {
33
+ const {
34
+ onSearch, onInputUpdate, items, actionText, patternfly4, autoSearchEnabled, ...rest
35
+ } = this.props;
36
+
37
+ const activeItems = getActiveItems(items);
38
+
39
+ return (
40
+ <Downshift
41
+ onStateChange={this.handleStateChange}
42
+ defaultHighlightedIndex={0}
43
+ selectedItem={this.state.inputValue}
44
+ {...rest}
45
+ >
46
+ {({
47
+ getInputProps,
48
+ getItemProps,
49
+ isOpen,
50
+ inputValue,
51
+ highlightedIndex,
52
+ selectedItem,
53
+ selectItem,
54
+ openMenu,
55
+ }) => {
56
+ const typeAheadProps = {
57
+ userInputValue: this.state.inputValue,
58
+ clearSearch: this.clearSearch,
59
+ getInputProps,
60
+ getItemProps,
61
+ isOpen,
62
+ inputValue,
63
+ highlightedIndex,
64
+ selectedItem,
65
+ selectItem,
66
+ openMenu,
67
+ onSearch,
68
+ items,
69
+ activeItems,
70
+ shouldShowItems: isOpen && items.length > 0,
71
+ };
72
+
73
+ return (
74
+ <div>
75
+ {patternfly4 ?
76
+ <TypeAheadSearchPf4 autoSearchEnabled={autoSearchEnabled} {...typeAheadProps} /> :
77
+ <TypeAheadSearch actionText={actionText} {...typeAheadProps} />}
78
+ </div>
79
+ );
80
+ }}
81
+ </Downshift>
82
+ );
83
+ }
84
+ }
85
+
86
+ TypeAhead.propTypes = {
87
+ items: PropTypes.arrayOf(PropTypes.shape({
88
+ /* text to display in MenuItem */
89
+ text: PropTypes.string,
90
+ /* item can be a header or divider or undefined for regular item */
91
+ type: PropTypes.oneOf(['header', 'divider']),
92
+ /* optionally disable a regular item */
93
+ disabled: PropTypes.bool,
94
+ })).isRequired,
95
+ onInputUpdate: PropTypes.func.isRequired,
96
+ onSearch: PropTypes.func.isRequired,
97
+ actionText: PropTypes.string,
98
+ initialInputValue: PropTypes.string,
99
+ patternfly4: PropTypes.bool,
100
+ autoSearchEnabled: PropTypes.bool.isRequired,
101
+ };
102
+
103
+ TypeAhead.defaultProps = {
104
+ actionText: 'Search',
105
+ initialInputValue: '',
106
+ patternfly4: false,
107
+ };
108
+
109
+ export default TypeAhead;
@@ -0,0 +1,35 @@
1
+ import PropTypes from 'prop-types';
2
+
3
+ const commonSearchPropTypes = {
4
+ userInputValue: PropTypes.string.isRequired,
5
+ clearSearch: PropTypes.func.isRequired,
6
+ getInputProps: PropTypes.func.isRequired,
7
+ getItemProps: PropTypes.func.isRequired,
8
+ isOpen: PropTypes.bool.isRequired,
9
+ inputValue: PropTypes.string.isRequired,
10
+ highlightedIndex: PropTypes.number.isRequired,
11
+ selectedItem: PropTypes.string.isRequired,
12
+ selectItem: PropTypes.func.isRequired,
13
+ openMenu: PropTypes.func.isRequired,
14
+ onSearch: PropTypes.func.isRequired,
15
+ items: PropTypes.arrayOf(PropTypes.shape({
16
+ text: PropTypes.string,
17
+ })).isRequired,
18
+ activeItems: PropTypes.arrayOf(PropTypes.string).isRequired,
19
+ shouldShowItems: PropTypes.bool.isRequired,
20
+ };
21
+
22
+ export const commonInputPropTypes = {
23
+ passedProps: PropTypes.shape({}).isRequired,
24
+ onKeyPress: PropTypes.func.isRequired,
25
+ onInputFocus: PropTypes.func.isRequired,
26
+ };
27
+
28
+ export const commonItemPropTypes = {
29
+ items: PropTypes.arrayOf(PropTypes.object).isRequired,
30
+ activeItems: PropTypes.arrayOf(PropTypes.string).isRequired,
31
+ highlightedIndex: PropTypes.number.isRequired,
32
+ getItemProps: PropTypes.func.isRequired,
33
+ };
34
+
35
+ export default commonSearchPropTypes;
@@ -0,0 +1,32 @@
1
+ import { KEYCODES } from 'foremanReact/common/keyCodes';
2
+
3
+ const keyPressHandler = (
4
+ e, isOpen, activeItems, highlightedIndex,
5
+ selectItem, userInputValue, onSearch,
6
+ ) => {
7
+ switch (e.keyCode) {
8
+ case KEYCODES.TAB_KEY:
9
+ if (isOpen && activeItems[highlightedIndex]) {
10
+ selectItem(activeItems[highlightedIndex]);
11
+ e.preventDefault();
12
+ }
13
+ break;
14
+
15
+ case KEYCODES.ENTER:
16
+ if (!isOpen || !activeItems[highlightedIndex]) {
17
+ onSearch(userInputValue);
18
+ e.preventDefault();
19
+ }
20
+ break;
21
+
22
+ default:
23
+ break;
24
+ }
25
+ };
26
+
27
+ export const getActiveItems = items =>
28
+ items
29
+ .filter(({ disabled, type }) => !disabled && !['header', 'divider'].includes(type))
30
+ .map(({ text }) => text);
31
+
32
+ export default keyPressHandler;
@@ -0,0 +1,3 @@
1
+ import TypeAhead from './TypeAhead';
2
+
3
+ export default TypeAhead;
@@ -1,7 +1,8 @@
1
1
  import React, { Component } from 'react';
2
- import PropTypes from 'prop-types';
3
2
  import { FormControl } from 'patternfly-react';
4
3
 
4
+ import { commonInputPropTypes } from '../helpers/commonPropTypes';
5
+
5
6
  class TypeAheadInput extends Component {
6
7
  constructor(props) {
7
8
  super(props);
@@ -38,10 +39,6 @@ class TypeAheadInput extends Component {
38
39
  }
39
40
  }
40
41
 
41
- TypeAheadInput.propTypes = {
42
- passedProps: PropTypes.shape({}).isRequired,
43
- onKeyPress: PropTypes.func.isRequired,
44
- onInputFocus: PropTypes.func.isRequired,
45
- };
42
+ TypeAheadInput.propTypes = commonInputPropTypes;
46
43
 
47
44
  export default TypeAheadInput;
@@ -1,7 +1,8 @@
1
1
  import React from 'react';
2
- import PropTypes from 'prop-types';
3
2
  import { Dropdown, MenuItem } from 'patternfly-react';
4
3
 
4
+ import { commonItemPropTypes } from '../helpers/commonPropTypes';
5
+
5
6
  const TypeAheadItems = ({
6
7
  items, activeItems, getItemProps, highlightedIndex,
7
8
  }) => (
@@ -50,11 +51,6 @@ const TypeAheadItems = ({
50
51
  </Dropdown.Menu>
51
52
  );
52
53
 
53
- TypeAheadItems.propTypes = {
54
- items: PropTypes.arrayOf(PropTypes.object).isRequired,
55
- activeItems: PropTypes.arrayOf(PropTypes.string).isRequired,
56
- highlightedIndex: PropTypes.number.isRequired,
57
- getItemProps: PropTypes.func.isRequired,
58
- };
54
+ TypeAheadItems.propTypes = commonItemPropTypes;
59
55
 
60
56
  export default TypeAheadItems;
@@ -0,0 +1,52 @@
1
+ import React from 'react';
2
+ import { InputGroup, Button, Icon } from 'patternfly-react';
3
+ import PropTypes from 'prop-types';
4
+
5
+ import TypeAheadInput from './TypeAheadInput';
6
+ import TypeAheadItems from './TypeAheadItems';
7
+ import keyPressHandler from '../helpers/helpers';
8
+ import commonSearchPropTypes from '../helpers/commonPropTypes';
9
+
10
+ const TypeAheadSearch = ({
11
+ userInputValue, clearSearch, getInputProps, getItemProps, isOpen, inputValue, highlightedIndex,
12
+ selectedItem, selectItem, openMenu, onSearch, items, activeItems, actionText, shouldShowItems,
13
+ }) => (
14
+ <div>
15
+ <InputGroup>
16
+ <TypeAheadInput
17
+ onKeyPress={e => keyPressHandler(
18
+ e, isOpen, activeItems, highlightedIndex,
19
+ selectItem, userInputValue, onSearch,
20
+ )}
21
+ onInputFocus={openMenu}
22
+ passedProps={getInputProps()}
23
+ />
24
+ {userInputValue &&
25
+ <InputGroup.Button>
26
+ <Button onClick={clearSearch}>
27
+ <Icon name="times" />
28
+ </Button>
29
+ </InputGroup.Button>
30
+ }
31
+ <InputGroup.Button>
32
+ <Button aria-label="patternfly 3 search button" onClick={() => onSearch(inputValue)}>{actionText}</Button>
33
+ </InputGroup.Button>
34
+ </InputGroup>
35
+
36
+ {shouldShowItems && <TypeAheadItems {...{
37
+ items, highlightedIndex, selectedItem, getItemProps, activeItems,
38
+ }}
39
+ />}
40
+ </div>
41
+ );
42
+
43
+ TypeAheadSearch.propTypes = {
44
+ ...commonSearchPropTypes,
45
+ actionText: PropTypes.string,
46
+ };
47
+
48
+ TypeAheadSearch.defaultProps = {
49
+ actionText: 'Search',
50
+ };
51
+
52
+ export default TypeAheadSearch;
@@ -0,0 +1,44 @@
1
+ import React, { useRef } from 'react';
2
+ import PropTypes from 'prop-types';
3
+ import { TextInput } from '@patternfly/react-core';
4
+ import { SearchIcon } from '@patternfly/react-icons';
5
+
6
+ import useEventListener from '../../../utils/useEventListener';
7
+ import { commonInputPropTypes } from '../helpers/commonPropTypes';
8
+
9
+ import './TypeAheadInput.scss';
10
+
11
+ const TypeAheadInput = ({
12
+ onKeyPress, onInputFocus, passedProps, autoSearchEnabled,
13
+ }) => {
14
+ const inputRef = useRef(null);
15
+ const { onChange, ...downshiftProps } = passedProps;
16
+
17
+ // What patternfly4 expects for args and what downshift creates as a function is different,
18
+ // downshift only expects the event handler
19
+ const onChangeWrapper = (_userValue, event) => onChange(event);
20
+
21
+ useEventListener('keydown', onKeyPress, inputRef.current);
22
+
23
+ return (
24
+ <React.Fragment>
25
+ <TextInput
26
+ {...downshiftProps}
27
+ ref={inputRef}
28
+ onFocus={onInputFocus}
29
+ aria-label="text input for search"
30
+ onChange={onChangeWrapper}
31
+ className={autoSearchEnabled ? 'foreman-pf4-search-input' : ''}
32
+ type="search"
33
+ />
34
+ {autoSearchEnabled && <SearchIcon size="sm" className="foreman-pf4-search-icon" />}
35
+ </React.Fragment>
36
+ );
37
+ };
38
+
39
+ TypeAheadInput.propTypes = {
40
+ autoSearchEnabled: PropTypes.bool.isRequired,
41
+ ...commonInputPropTypes,
42
+ };
43
+
44
+ export default TypeAheadInput;
@@ -0,0 +1,11 @@
1
+ // Influenced by https://github.com/RedHatInsights/frontend-components/blob/41d66f3227e582a081af5f445dbdea3f97fe5160/packages/components/src/Components/ConditionalFilter/conditional-filter.scss
2
+
3
+ .foreman-pf4-search-icon {
4
+ position: relative;
5
+ height: auto;
6
+ }
7
+
8
+ .foreman-pf4-search-input {
9
+ padding-right: 35px;
10
+ margin-right: -23px;
11
+ }