katello 4.18.1 → 4.19.0.rc1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of katello might be problematic. Click here for more details.

Files changed (336) hide show
  1. checksums.yaml +4 -4
  2. data/app/assets/javascripts/katello/locale/bn/katello.js +56 -107
  3. data/app/assets/javascripts/katello/locale/bn_IN/katello.js +56 -107
  4. data/app/assets/javascripts/katello/locale/ca/katello.js +56 -107
  5. data/app/assets/javascripts/katello/locale/cs/katello.js +56 -107
  6. data/app/assets/javascripts/katello/locale/cs_CZ/katello.js +57 -108
  7. data/app/assets/javascripts/katello/locale/de/katello.js +58 -109
  8. data/app/assets/javascripts/katello/locale/de_AT/katello.js +56 -107
  9. data/app/assets/javascripts/katello/locale/de_DE/katello.js +56 -107
  10. data/app/assets/javascripts/katello/locale/el/katello.js +57 -108
  11. data/app/assets/javascripts/katello/locale/en/katello.js +56 -107
  12. data/app/assets/javascripts/katello/locale/en_GB/katello.js +56 -107
  13. data/app/assets/javascripts/katello/locale/en_US/katello.js +56 -107
  14. data/app/assets/javascripts/katello/locale/es/katello.js +58 -109
  15. data/app/assets/javascripts/katello/locale/et_EE/katello.js +56 -107
  16. data/app/assets/javascripts/katello/locale/fr/katello.js +59 -110
  17. data/app/assets/javascripts/katello/locale/gl/katello.js +56 -107
  18. data/app/assets/javascripts/katello/locale/gu/katello.js +56 -107
  19. data/app/assets/javascripts/katello/locale/he_IL/katello.js +56 -107
  20. data/app/assets/javascripts/katello/locale/hi/katello.js +56 -107
  21. data/app/assets/javascripts/katello/locale/id/katello.js +56 -107
  22. data/app/assets/javascripts/katello/locale/it/katello.js +56 -107
  23. data/app/assets/javascripts/katello/locale/ja/katello.js +59 -110
  24. data/app/assets/javascripts/katello/locale/ka/katello.js +58 -109
  25. data/app/assets/javascripts/katello/locale/kn/katello.js +56 -107
  26. data/app/assets/javascripts/katello/locale/ko/katello.js +59 -110
  27. data/app/assets/javascripts/katello/locale/ml_IN/katello.js +56 -107
  28. data/app/assets/javascripts/katello/locale/mr/katello.js +56 -107
  29. data/app/assets/javascripts/katello/locale/nl_NL/katello.js +56 -107
  30. data/app/assets/javascripts/katello/locale/or/katello.js +56 -107
  31. data/app/assets/javascripts/katello/locale/pa/katello.js +56 -107
  32. data/app/assets/javascripts/katello/locale/pl/katello.js +56 -107
  33. data/app/assets/javascripts/katello/locale/pl_PL/katello.js +56 -107
  34. data/app/assets/javascripts/katello/locale/pt/katello.js +56 -107
  35. data/app/assets/javascripts/katello/locale/pt_BR/katello.js +58 -109
  36. data/app/assets/javascripts/katello/locale/ro/katello.js +56 -107
  37. data/app/assets/javascripts/katello/locale/ro_RO/katello.js +56 -107
  38. data/app/assets/javascripts/katello/locale/ru/katello.js +57 -108
  39. data/app/assets/javascripts/katello/locale/sl/katello.js +56 -107
  40. data/app/assets/javascripts/katello/locale/sv_SE/katello.js +56 -107
  41. data/app/assets/javascripts/katello/locale/ta/katello.js +56 -107
  42. data/app/assets/javascripts/katello/locale/ta_IN/katello.js +56 -107
  43. data/app/assets/javascripts/katello/locale/te/katello.js +56 -107
  44. data/app/assets/javascripts/katello/locale/tr/katello.js +56 -107
  45. data/app/assets/javascripts/katello/locale/vi/katello.js +56 -107
  46. data/app/assets/javascripts/katello/locale/vi_VN/katello.js +56 -107
  47. data/app/assets/javascripts/katello/locale/zh/katello.js +56 -107
  48. data/app/assets/javascripts/katello/locale/zh_CN/katello.js +59 -110
  49. data/app/assets/javascripts/katello/locale/zh_TW/katello.js +57 -108
  50. data/app/controllers/katello/api/registry/registry_proxies_controller.rb +41 -12
  51. data/app/controllers/katello/api/rhsm/candlepin_proxies_controller.rb +1 -1
  52. data/app/controllers/katello/api/v2/activation_keys_controller.rb +3 -65
  53. data/app/controllers/katello/api/v2/content_view_filter_rules_controller.rb +1 -1
  54. data/app/controllers/katello/api/v2/content_views_controller.rb +18 -3
  55. data/app/controllers/katello/api/v2/debs_controller.rb +21 -11
  56. data/app/controllers/katello/api/v2/docker_tags_controller.rb +7 -0
  57. data/app/controllers/katello/api/v2/flatpak_remote_repositories_controller.rb +21 -19
  58. data/app/controllers/katello/api/v2/host_debs_controller.rb +16 -1
  59. data/app/controllers/katello/api/v2/host_subscriptions_controller.rb +3 -60
  60. data/app/controllers/katello/api/v2/hosts_bulk_actions_controller.rb +10 -53
  61. data/app/controllers/katello/api/v2/repositories_controller.rb +0 -1
  62. data/app/controllers/katello/concerns/organizations_controller_extensions.rb +3 -0
  63. data/app/lib/actions/candlepin/activation_key/create.rb +0 -2
  64. data/app/lib/actions/candlepin/activation_key/update.rb +0 -2
  65. data/app/lib/actions/candlepin/product/content_create.rb +3 -5
  66. data/app/lib/actions/candlepin/product/content_update.rb +2 -3
  67. data/app/lib/actions/helpers/rolling_cv_repos.rb +1 -1
  68. data/app/lib/actions/katello/activation_key/create.rb +0 -1
  69. data/app/lib/actions/katello/activation_key/update.rb +0 -2
  70. data/app/lib/actions/katello/capsule_content/sync_capsule.rb +1 -6
  71. data/app/lib/actions/katello/content_credential/update.rb +1 -1
  72. data/app/lib/actions/katello/content_view/add_rolling_repo_clone.rb +18 -24
  73. data/app/lib/actions/katello/content_view/create.rb +9 -4
  74. data/app/lib/actions/katello/content_view/refresh_rolling_repo.rb +6 -1
  75. data/app/lib/actions/katello/content_view/remove_rolling_repo_clone.rb +16 -11
  76. data/app/lib/actions/katello/content_view/update.rb +34 -7
  77. data/app/lib/actions/katello/product/content_create.rb +2 -2
  78. data/app/lib/actions/katello/product/content_destroy.rb +1 -1
  79. data/app/lib/actions/katello/repository/check_matching_content.rb +1 -1
  80. data/app/lib/actions/katello/repository/clone_contents.rb +1 -1
  81. data/app/lib/actions/katello/repository/create.rb +1 -1
  82. data/app/lib/actions/katello/repository/destroy.rb +4 -4
  83. data/app/lib/actions/katello/repository/finish_upload.rb +1 -1
  84. data/app/lib/actions/katello/repository/sync.rb +1 -1
  85. data/app/lib/actions/pulp3/orchestration/repository/copy_all_units.rb +2 -2
  86. data/app/lib/actions/pulp3/orchestration/repository/generate_metadata.rb +1 -1
  87. data/app/lib/actions/pulp3/orchestration/repository/multi_copy_all_units.rb +1 -1
  88. data/app/lib/actions/pulp3/repository/save_publication.rb +3 -1
  89. data/app/lib/actions/pulp3/repository/save_version.rb +45 -24
  90. data/app/lib/actions/pulp3/repository/save_versions.rb +2 -1
  91. data/app/lib/katello/resources/candlepin/activation_key.rb +3 -4
  92. data/app/lib/katello/resources/candlepin/upstream_job.rb +9 -1
  93. data/app/lib/katello/resources/candlepin.rb +4 -0
  94. data/app/models/katello/authorization/repository.rb +17 -4
  95. data/app/models/katello/concerns/subscription_facet_host_extensions.rb +0 -7
  96. data/app/models/katello/content_view_deb_filter.rb +10 -0
  97. data/app/models/katello/content_view_deb_filter_rule.rb +7 -0
  98. data/app/models/katello/deb.rb +10 -10
  99. data/app/models/katello/erratum.rb +1 -1
  100. data/app/models/katello/glue/provider.rb +14 -3
  101. data/app/models/katello/host/content_facet.rb +1 -1
  102. data/app/models/katello/host/subscription_facet.rb +1 -7
  103. data/app/models/katello/product_content.rb +2 -2
  104. data/app/models/katello/repository.rb +4 -23
  105. data/app/models/katello/root_repository.rb +2 -5
  106. data/app/services/katello/candlepin/event_handler.rb +0 -33
  107. data/app/services/katello/candlepin/message_handler.rb +0 -41
  108. data/app/services/katello/content_unit_indexer.rb +59 -13
  109. data/app/services/katello/product_content_finder.rb +5 -4
  110. data/app/services/katello/pulp3/alternate_content_source.rb +2 -2
  111. data/app/services/katello/pulp3/ansible_collection.rb +1 -0
  112. data/app/services/katello/pulp3/api/content_guard.rb +5 -5
  113. data/app/services/katello/pulp3/api/core.rb +10 -0
  114. data/app/services/katello/pulp3/deb.rb +1 -0
  115. data/app/services/katello/pulp3/docker_manifest.rb +1 -0
  116. data/app/services/katello/pulp3/docker_manifest_list.rb +1 -0
  117. data/app/services/katello/pulp3/docker_tag.rb +1 -0
  118. data/app/services/katello/pulp3/file_unit.rb +1 -0
  119. data/app/services/katello/pulp3/generic_content_unit.rb +1 -0
  120. data/app/services/katello/pulp3/module_stream.rb +1 -0
  121. data/app/services/katello/pulp3/package_group.rb +1 -0
  122. data/app/services/katello/pulp3/repository/apt.rb +30 -13
  123. data/app/services/katello/pulp3/repository.rb +59 -10
  124. data/app/services/katello/pulp3/rpm.rb +3 -2
  125. data/app/services/katello/pulp3/srpm.rb +3 -2
  126. data/app/services/katello/pulp3/task_group.rb +1 -1
  127. data/app/services/katello/registration_manager.rb +19 -17
  128. data/app/services/katello/repository_type_manager.rb +7 -5
  129. data/app/services/katello/smart_proxy_helper.rb +1 -6
  130. data/app/views/foreman/job_templates/upload_profile.erb +5 -0
  131. data/app/views/katello/api/v2/activation_keys/base.json.rabl +1 -1
  132. data/app/views/katello/api/v2/content_views/base.json.rabl +1 -0
  133. data/app/views/katello/api/v2/debs/thindex.json.rabl +6 -0
  134. data/app/views/katello/api/v2/docker_tags/_base.json.rabl +32 -0
  135. data/app/views/katello/api/v2/docker_tags/show.json.rabl +0 -5
  136. data/app/views/katello/api/v2/flatpak_remotes/index.json.rabl +6 -0
  137. data/app/views/katello/api/v2/host_debs/installed_debs.json.rabl +6 -0
  138. data/app/views/katello/api/v2/hosts_bulk_actions/applicable_errata.json.rabl +1 -1
  139. data/app/views/katello/api/v2/hosts_bulk_actions/applicable_erratum.json.rabl +9 -0
  140. data/app/views/katello/api/v2/hosts_bulk_actions/installable_errata.json.rabl +1 -1
  141. data/app/views/katello/api/v2/hosts_bulk_actions/{erratum.json.rabl → installable_erratum.json.rabl} +3 -3
  142. data/app/views/katello/api/v2/subscription_facet/base.json.rabl +1 -1
  143. data/config/initializers/monkeys.rb +1 -0
  144. data/config/routes/api/v2.rb +2 -2
  145. data/config/routes/overrides.rb +2 -7
  146. data/config/routes.rb +2 -0
  147. data/db/migrate/20211019192121_create_cdn_configuration.katello.rb +1 -1
  148. data/db/migrate/20250912000000_add_pulp_prn_fields.rb +73 -0
  149. data/db/migrate/20250912000001_populate_pulp_prn_fields.rb +403 -0
  150. data/db/migrate/20251009142516_remove_auto_attach_from_activation_keys.rb +5 -0
  151. data/db/migrate/20251009142517_remove_autoheal_from_subscription_facets.rb +5 -0
  152. data/db/seeds.d/111-upgrade_tasks.rb +2 -0
  153. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/i18n/locale/el.po +2 -2
  154. data/lib/katello/permission_creator.rb +2 -2
  155. data/lib/katello/permissions/host_permissions.rb +0 -6
  156. data/lib/katello/plugin.rb +16 -8
  157. data/lib/katello/tasks/jenkins.rake +1 -1
  158. data/lib/katello/tasks/upgrades/4.19/enable_structured_apt_for_deb.rake +87 -0
  159. data/lib/katello/tasks/upgrades/4.19/populate_repository_version_prns.rake +32 -0
  160. data/lib/katello/version.rb +1 -1
  161. data/lib/monkeys/fix_rpm_repository_gpgcheck.rb +38 -0
  162. data/locale/bn/LC_MESSAGES/katello.mo +0 -0
  163. data/locale/bn/katello.po +56 -107
  164. data/locale/bn_IN/LC_MESSAGES/katello.mo +0 -0
  165. data/locale/bn_IN/katello.po +56 -107
  166. data/locale/ca/LC_MESSAGES/katello.mo +0 -0
  167. data/locale/ca/katello.po +56 -107
  168. data/locale/cs/LC_MESSAGES/katello.mo +0 -0
  169. data/locale/cs/katello.po +56 -107
  170. data/locale/cs_CZ/LC_MESSAGES/katello.mo +0 -0
  171. data/locale/cs_CZ/katello.po +57 -108
  172. data/locale/de/LC_MESSAGES/katello.mo +0 -0
  173. data/locale/de/katello.po +58 -109
  174. data/locale/de_AT/LC_MESSAGES/katello.mo +0 -0
  175. data/locale/de_AT/katello.po +56 -107
  176. data/locale/de_DE/LC_MESSAGES/katello.mo +0 -0
  177. data/locale/de_DE/katello.po +56 -107
  178. data/locale/el/LC_MESSAGES/katello.mo +0 -0
  179. data/locale/el/katello.po +58 -109
  180. data/locale/en/LC_MESSAGES/katello.mo +0 -0
  181. data/locale/en/katello.po +56 -107
  182. data/locale/en_GB/LC_MESSAGES/katello.mo +0 -0
  183. data/locale/en_GB/katello.po +56 -107
  184. data/locale/en_US/LC_MESSAGES/katello.mo +0 -0
  185. data/locale/en_US/katello.po +56 -107
  186. data/locale/es/LC_MESSAGES/katello.mo +0 -0
  187. data/locale/es/katello.po +58 -109
  188. data/locale/et_EE/LC_MESSAGES/katello.mo +0 -0
  189. data/locale/et_EE/katello.po +56 -107
  190. data/locale/fr/LC_MESSAGES/katello.mo +0 -0
  191. data/locale/fr/katello.po +59 -110
  192. data/locale/gl/LC_MESSAGES/katello.mo +0 -0
  193. data/locale/gl/katello.po +56 -107
  194. data/locale/gu/LC_MESSAGES/katello.mo +0 -0
  195. data/locale/gu/katello.po +56 -107
  196. data/locale/he_IL/LC_MESSAGES/katello.mo +0 -0
  197. data/locale/he_IL/katello.po +56 -107
  198. data/locale/hi/LC_MESSAGES/katello.mo +0 -0
  199. data/locale/hi/katello.po +56 -107
  200. data/locale/id/LC_MESSAGES/katello.mo +0 -0
  201. data/locale/id/katello.po +56 -107
  202. data/locale/it/LC_MESSAGES/katello.mo +0 -0
  203. data/locale/it/katello.po +56 -107
  204. data/locale/ja/LC_MESSAGES/katello.mo +0 -0
  205. data/locale/ja/katello.po +59 -110
  206. data/locale/ka/LC_MESSAGES/katello.mo +0 -0
  207. data/locale/ka/katello.po +58 -109
  208. data/locale/katello.pot +676 -749
  209. data/locale/kn/LC_MESSAGES/katello.mo +0 -0
  210. data/locale/kn/katello.po +56 -107
  211. data/locale/ko/LC_MESSAGES/katello.mo +0 -0
  212. data/locale/ko/katello.po +59 -110
  213. data/locale/ml_IN/LC_MESSAGES/katello.mo +0 -0
  214. data/locale/ml_IN/katello.po +56 -107
  215. data/locale/mr/LC_MESSAGES/katello.mo +0 -0
  216. data/locale/mr/katello.po +56 -107
  217. data/locale/nl_NL/LC_MESSAGES/katello.mo +0 -0
  218. data/locale/nl_NL/katello.po +56 -107
  219. data/locale/or/LC_MESSAGES/katello.mo +0 -0
  220. data/locale/or/katello.po +56 -107
  221. data/locale/pa/LC_MESSAGES/katello.mo +0 -0
  222. data/locale/pa/katello.po +56 -107
  223. data/locale/pl/LC_MESSAGES/katello.mo +0 -0
  224. data/locale/pl/katello.po +56 -107
  225. data/locale/pl_PL/LC_MESSAGES/katello.mo +0 -0
  226. data/locale/pl_PL/katello.po +56 -107
  227. data/locale/pt/LC_MESSAGES/katello.mo +0 -0
  228. data/locale/pt/katello.po +56 -107
  229. data/locale/pt_BR/LC_MESSAGES/katello.mo +0 -0
  230. data/locale/pt_BR/katello.po +58 -109
  231. data/locale/ro/LC_MESSAGES/katello.mo +0 -0
  232. data/locale/ro/katello.po +56 -107
  233. data/locale/ro_RO/LC_MESSAGES/katello.mo +0 -0
  234. data/locale/ro_RO/katello.po +56 -107
  235. data/locale/ru/LC_MESSAGES/katello.mo +0 -0
  236. data/locale/ru/katello.po +57 -108
  237. data/locale/sl/LC_MESSAGES/katello.mo +0 -0
  238. data/locale/sl/katello.po +56 -107
  239. data/locale/sv_SE/LC_MESSAGES/katello.mo +0 -0
  240. data/locale/sv_SE/katello.po +56 -107
  241. data/locale/ta/LC_MESSAGES/katello.mo +0 -0
  242. data/locale/ta/katello.po +56 -107
  243. data/locale/ta_IN/LC_MESSAGES/katello.mo +0 -0
  244. data/locale/ta_IN/katello.po +56 -107
  245. data/locale/te/LC_MESSAGES/katello.mo +0 -0
  246. data/locale/te/katello.po +56 -107
  247. data/locale/tr/LC_MESSAGES/katello.mo +0 -0
  248. data/locale/tr/katello.po +56 -107
  249. data/locale/vi/LC_MESSAGES/katello.mo +0 -0
  250. data/locale/vi/katello.po +56 -107
  251. data/locale/vi_VN/LC_MESSAGES/katello.mo +0 -0
  252. data/locale/vi_VN/katello.po +56 -107
  253. data/locale/zh/LC_MESSAGES/katello.mo +0 -0
  254. data/locale/zh/katello.po +56 -107
  255. data/locale/zh_CN/LC_MESSAGES/katello.mo +0 -0
  256. data/locale/zh_CN/katello.po +59 -110
  257. data/locale/zh_TW/LC_MESSAGES/katello.mo +0 -0
  258. data/locale/zh_TW/katello.po +57 -108
  259. data/webpack/components/Content/Details/__tests__/__snapshots__/ContentDetails.test.js.snap +2 -2
  260. data/webpack/components/extensions/HostDetails/Cards/SystemPurposeCard/SystemPurposeEditModal.js +0 -2
  261. data/webpack/components/extensions/HostDetails/Cards/SystemPurposeCard/__tests__/SystemPurposeEditModal.test.js +0 -2
  262. data/webpack/components/extensions/Hosts/ActionsBar/index.js +1 -0
  263. data/webpack/components/extensions/Hosts/BulkActions/BulkActionsConstants.js +7 -0
  264. data/webpack/components/extensions/Hosts/BulkActions/BulkChangeHostCollectionsModal/BulkChangeHostCollectionsModal.js +388 -0
  265. data/webpack/components/extensions/Hosts/BulkActions/BulkChangeHostCollectionsModal/__tests__/BulkChangeHostCollectionsModal.test.js +640 -0
  266. data/webpack/components/extensions/Hosts/BulkActions/BulkChangeHostCollectionsModal/actions.js +28 -0
  267. data/webpack/components/extensions/Hosts/BulkActions/BulkChangeHostCollectionsModal/index.js +71 -0
  268. data/webpack/components/extensions/Hosts/BulkActions/BulkErrataWizard/BulkErrataWizard.js +1 -1
  269. data/webpack/components/extensions/Hosts/BulkActions/BulkPackagesWizard/02_BulkPackagesTable.js +10 -3
  270. data/webpack/components/extensions/Hosts/BulkActions/BulkPackagesWizard/BulkPackagesWizard.js +51 -24
  271. data/webpack/components/extensions/Hosts/BulkActions/HostReview.js +7 -0
  272. data/webpack/containers/Application/config.js +11 -1
  273. data/webpack/global_index.js +3 -0
  274. data/webpack/scenes/{BootedContainerImages → ContainerImages/Booted}/BootedContainerImagesConstants.js +1 -1
  275. data/webpack/scenes/{BootedContainerImages → ContainerImages/Booted}/BootedContainerImagesPage.js +7 -43
  276. data/webpack/scenes/{BootedContainerImages → ContainerImages/Booted}/__tests__/bootedContainerImagesPage.test.js +1 -1
  277. data/webpack/scenes/ContainerImages/ContainerImagesPage.js +86 -0
  278. data/webpack/scenes/ContainerImages/LabelsAnnotationsModal.js +105 -0
  279. data/webpack/scenes/ContainerImages/Synced/Details/ManifestDetails.js +218 -0
  280. data/webpack/scenes/ContainerImages/Synced/Details/ManifestDetailsActions.js +15 -0
  281. data/webpack/scenes/ContainerImages/Synced/Details/ManifestDetailsSelectors.js +16 -0
  282. data/webpack/scenes/ContainerImages/Synced/Details/__tests__/ManifestDetails.test.js +395 -0
  283. data/webpack/scenes/ContainerImages/Synced/Details/__tests__/manifestDetails.fixtures.json +43 -0
  284. data/webpack/scenes/ContainerImages/Synced/Details/__tests__/manifestList.fixtures.json +58 -0
  285. data/webpack/scenes/ContainerImages/Synced/Details/index.js +4 -0
  286. data/webpack/scenes/ContainerImages/Synced/SyncedContainerImagesPage.js +359 -0
  287. data/webpack/scenes/ContainerImages/Synced/SyncedContainerImagesPage.scss +21 -0
  288. data/webpack/scenes/ContainerImages/Synced/__tests__/LabelsAnnotationsModal.test.js +69 -0
  289. data/webpack/scenes/ContainerImages/Synced/__tests__/SyncedContainerImagesPage.test.js +335 -0
  290. data/webpack/scenes/ContainerImages/Synced/__tests__/syncedContainerImages.fixtures.json +105 -0
  291. data/webpack/scenes/ContainerImages/TableEmptyState.js +67 -0
  292. data/webpack/scenes/ContainerImages/containerImagesHelpers.js +48 -0
  293. data/webpack/scenes/ContainerImages/index.js +4 -0
  294. data/webpack/scenes/ContentViews/Create/CreateContentViewForm.js +29 -3
  295. data/webpack/scenes/ContentViews/Create/__tests__/contentViewCreateResult.fixtures.json +1 -0
  296. data/webpack/scenes/ContentViews/Create/__tests__/createContentView.test.js +45 -1
  297. data/webpack/scenes/ContentViews/Delete/__tests__/affectedHosts.fixtures.json +0 -1
  298. data/webpack/scenes/ContentViews/Details/ContentViewInfo.js +59 -1
  299. data/webpack/scenes/ContentViews/Details/Filters/CVDebFilterContent.js +1 -0
  300. data/webpack/scenes/ContentViews/Details/Filters/Rules/DebPackage/AddEditDebPackageRuleModal.js +164 -24
  301. data/webpack/scenes/ContentViews/Details/Filters/__tests__/CVDebFilterContent.test.js +268 -0
  302. data/webpack/scenes/ContentViews/Details/Filters/__tests__/cvDebFilterDetail.fixtures.json +95 -0
  303. data/webpack/scenes/ContentViews/Details/Filters/__tests__/cvDebFilterRules.fixtures.json +31 -0
  304. data/webpack/scenes/ContentViews/Details/Filters/__tests__/emptyCVDebFilterRules.fixtures.json +10 -0
  305. data/webpack/scenes/ContentViews/Details/Versions/BulkDelete/__tests__/hosts.fixtures.json +0 -1
  306. data/webpack/scenes/ContentViews/Details/Versions/Delete/__tests__/cvAffectedHosts.fixture.json +0 -1
  307. data/webpack/scenes/ContentViews/Details/__tests__/contentViewRollingDetail.test.js +15 -0
  308. data/webpack/scenes/ContentViews/Details/__tests__/contentViewRollingDetails.fixtures.json +1 -0
  309. data/webpack/scenes/ContentViews/__tests__/contentViewPage.test.js +9 -0
  310. data/webpack/scenes/FlatpakRemotes/CreateEdit/CreateFlatpakRemoteModal.js +5 -3
  311. data/webpack/scenes/FlatpakRemotes/CreateEdit/EditFlatpakRemotesModal.js +1 -1
  312. data/webpack/scenes/FlatpakRemotes/CreateEdit/FlatpakRemoteform.js +35 -3
  313. data/webpack/scenes/FlatpakRemotes/Details/FlatpakRemoteDetails.js +1 -1
  314. data/webpack/scenes/FlatpakRemotes/Details/RemoteRepositories/RemoteRepositoriesTable.css +3 -0
  315. data/webpack/scenes/FlatpakRemotes/Details/RemoteRepositories/RemoteRepositoriesTable.js +63 -132
  316. data/webpack/scenes/FlatpakRemotes/FlatpakRemotesPage.js +67 -143
  317. data/webpack/scenes/SmartProxy/ExpandableCvDetails.js +10 -2
  318. data/webpack/scenes/SmartProxy/SmartProxyContentActions.js +13 -2
  319. data/webpack/scenes/SmartProxy/SmartProxyContentConstants.js +1 -0
  320. data/webpack/scenes/SmartProxy/SmartProxyExpandableTable.js +8 -2
  321. data/webpack/scenes/SmartProxy/__tests__/SmartProxyContentTest.js +67 -1
  322. data/webpack/scenes/Subscriptions/Details/__tests__/__snapshots__/SubscriptionDetails.test.js.snap +2 -2
  323. data/webpack/scenes/Subscriptions/SubscriptionConstants.js +0 -2
  324. data/webpack/scenes/Subscriptions/__tests__/__snapshots__/SubscriptionsActions.test.js.snap +2 -2
  325. metadata +83 -55
  326. data/app/lib/actions/katello/host/attach_subscriptions.rb +0 -59
  327. data/app/lib/actions/katello/host/auto_attach_subscriptions.rb +0 -22
  328. data/app/lib/actions/katello/host/remove_subscriptions.rb +0 -50
  329. data/app/lib/actions/katello/organization/simple_content_access/disable.rb +0 -25
  330. data/app/lib/actions/katello/organization/simple_content_access/enable.rb +0 -25
  331. data/app/lib/actions/katello/organization/simple_content_access/toggle.rb +0 -42
  332. data/lib/katello/tasks/migrate_structure_content_for_deb.rake +0 -105
  333. data/lib/katello/tasks/upgrades/4.2/remove_checksum_values.rake +0 -17
  334. data/locale/action_names.rb +0 -186
  335. /data/webpack/scenes/{BootedContainerImages → ContainerImages/Booted}/__tests__/bootedContainerImages.fixtures.js +0 -0
  336. /data/webpack/scenes/{BootedContainerImages → ContainerImages/Booted}/index.js +0 -0
@@ -0,0 +1,71 @@
1
+ import React, { useContext } from 'react';
2
+ import PropTypes from 'prop-types';
3
+ import { MenuItem } from '@patternfly/react-core';
4
+ import { BanIcon } from '@patternfly/react-icons';
5
+ import { translate as __ } from 'foremanReact/common/I18n';
6
+ import { useForemanOrganization } from 'foremanReact/Root/Context/ForemanContext';
7
+ import { ForemanActionsBarContext } from 'foremanReact/components/HostDetails/ActionsBar';
8
+ import { useForemanModal } from 'foremanReact/components/ForemanModal/ForemanModalHooks';
9
+ import BulkChangeHostCollectionsModal from './BulkChangeHostCollectionsModal';
10
+
11
+ const DisabledMenuItemDescription = ({ disabledReason }) => (
12
+ <span className="disabled-menu-item-span">
13
+ <span className="disabled-menu-item-icon">
14
+ <BanIcon />
15
+ </span>
16
+ <p className="disabled-menu-item-p">
17
+ {disabledReason}
18
+ </p>
19
+ </span>
20
+ );
21
+
22
+ DisabledMenuItemDescription.propTypes = {
23
+ disabledReason: PropTypes.string.isRequired,
24
+ };
25
+
26
+ // This component renders only the MenuItem trigger (for the slot in the menu)
27
+ export const BulkChangeHostCollectionsMenuItem = ({ selectedCount }) => {
28
+ const orgId = useForemanOrganization()?.id;
29
+ const { setModalOpen } = useForemanModal({ id: 'bulk-change-host-collections-modal' });
30
+
31
+ return (
32
+ <MenuItem
33
+ itemId="change-host-collections-dropdown-item"
34
+ key="change-host-collections-dropdown-item"
35
+ onClick={setModalOpen}
36
+ isDisabled={selectedCount === 0 || !orgId}
37
+ description={!orgId && <DisabledMenuItemDescription disabledReason={__('To manage host collections, a specific organization must be selected from the organization context.')} />}
38
+ >
39
+ {__('Host collections')}
40
+ </MenuItem>
41
+ );
42
+ };
43
+
44
+ BulkChangeHostCollectionsMenuItem.propTypes = {
45
+ selectedCount: PropTypes.number,
46
+ };
47
+
48
+ BulkChangeHostCollectionsMenuItem.defaultProps = {
49
+ selectedCount: 0,
50
+ };
51
+
52
+ // This component renders only the modal (for the _all-hosts-modals slot)
53
+ const BulkChangeHostCollectionsModalScene = () => {
54
+ const orgId = useForemanOrganization()?.id;
55
+ const { selectedCount, fetchBulkParams } = useContext(ForemanActionsBarContext);
56
+ const { modalOpen, setModalClosed } = useForemanModal({ id: 'bulk-change-host-collections-modal' });
57
+
58
+ if (!orgId) return null;
59
+
60
+ return (
61
+ <BulkChangeHostCollectionsModal
62
+ key="bulk-change-host-collections-modal"
63
+ fetchBulkParams={fetchBulkParams}
64
+ selectedCount={selectedCount}
65
+ isOpen={modalOpen}
66
+ closeModal={setModalClosed}
67
+ />
68
+ );
69
+ };
70
+
71
+ export default BulkChangeHostCollectionsModalScene;
@@ -51,7 +51,7 @@ export const useErrataHostsBulkSelect = ({ initialSelectedHosts, modalIsOpen })
51
51
  };
52
52
  };
53
53
 
54
- export const ERRATA_URL = `${katelloApi.getApiUrl('/errata')}?per_page=7&include_permissions=true`;
54
+ export const ERRATA_URL = `${katelloApi.getApiUrl('/errata')}?per_page=7&include_permissions=true&errata_restrict_installable=true`;
55
55
 
56
56
  const BulkErrataWizard = () => {
57
57
  const { modalOpen, setModalClosed: closeModal } = useForemanModal({ id: 'bulk-errata-wizard' });
@@ -16,6 +16,7 @@ import { RowSelectTd } from 'foremanReact/components/HostsIndex/RowSelectTd';
16
16
  import { getPageStats } from 'foremanReact/components/PF4/TableIndexPage/Table/helpers';
17
17
  import { BulkPackagesWizardContext, getPackagesUrl } from './BulkPackagesWizard';
18
18
  import katelloApi from '../../../../../services/api';
19
+ import PACKAGE_CONTENT_TYPE_NAMES from '../BulkActionsConstants';
19
20
 
20
21
  export const BulkPackagesUpgradeTable = props => <BulkPackagesTable {...props} tableType="upgrade" />;
21
22
  export const BulkPackagesInstallTable = props => <BulkPackagesTable {...props} tableType="install" />;
@@ -23,6 +24,7 @@ export const BulkPackagesRemoveTable = props => <BulkPackagesTable {...props} ta
23
24
 
24
25
  const BulkPackagesTable = ({
25
26
  tableType,
27
+ contentTypeName,
26
28
  }) => {
27
29
  const {
28
30
  setShouldValidateStep2,
@@ -42,12 +44,12 @@ const BulkPackagesTable = ({
42
44
  upgrade: __('Select packages to upgrade to the latest version. Packages may have different versions on different hosts.'),
43
45
  };
44
46
 
45
- const origSearchProps = getControllerSearchProps('packages', 'searchBar-packages');
47
+ const origSearchProps = getControllerSearchProps(contentTypeName, 'searchBar-packages');
46
48
  const customSearchProps = {
47
49
  ...origSearchProps,
48
50
  autocomplete: {
49
51
  ...origSearchProps.autocomplete,
50
- url: katelloApi.getApiUrl('/packages/auto_complete_search'),
52
+ url: katelloApi.getApiUrl(`/${contentTypeName}/auto_complete_search`),
51
53
  },
52
54
  };
53
55
 
@@ -93,7 +95,7 @@ const BulkPackagesTable = ({
93
95
  name: {
94
96
  title: __('Package'),
95
97
  wrapper: ({ name, id }) => (
96
- <a target="_blank" href={tableType === 'remove' ? `/packages?search=${name}` : `/packages/${id}`} rel="noreferrer">{name}</a>
98
+ <a target="_blank" href={tableType === 'remove' ? `/${contentTypeName}?search=${name}` : `/${contentTypeName}/${id}`} rel="noreferrer">{name}</a>
97
99
  ),
98
100
  isSorted: true,
99
101
  weight: 50,
@@ -152,4 +154,9 @@ const BulkPackagesTable = ({
152
154
 
153
155
  BulkPackagesTable.propTypes = {
154
156
  tableType: PropTypes.string.isRequired,
157
+ contentTypeName: PropTypes.string,
158
+ };
159
+
160
+ BulkPackagesTable.defaultProps = {
161
+ contentTypeName: PACKAGE_CONTENT_TYPE_NAMES.REDHAT,
155
162
  };
@@ -22,6 +22,7 @@ import { BulkPackagesReview, dropdownOptions } from './04_Review';
22
22
  import { BulkPackagesUpgradeTable, BulkPackagesInstallTable, BulkPackagesRemoveTable } from './02_BulkPackagesTable';
23
23
  import { BulkPackagesReviewFooter } from './04_ReviewFooter';
24
24
  import katelloApi, { foremanApi } from '../../../../../services/api';
25
+ import PACKAGE_CONTENT_TYPE_NAMES from '../BulkActionsConstants';
25
26
 
26
27
  export const UPGRADE_ALL = 'upgradeAll';
27
28
  export const UPGRADE = 'upgrade';
@@ -62,18 +63,18 @@ export const useHostsBulkSelect = ({ initialSelectedHosts, modalIsOpen }) => {
62
63
  };
63
64
  };
64
65
 
65
- export const getPackagesUrl = (selectedAction) => {
66
+ export const getPackagesUrl = (selectedAction, contentTypeName) => {
67
+ if (contentTypeName === PACKAGE_CONTENT_TYPE_NAMES.INVALID) return '';
66
68
  if (selectedAction === REMOVE) {
67
- return `${foremanApi.getApiUrl('/hosts/host_packages/installed_packages')}?per_page=7&include_permissions=true`;
69
+ return `${foremanApi.getApiUrl(`/hosts/host_${contentTypeName}/installed_${contentTypeName}`)}?per_page=7&include_permissions=true`;
68
70
  }
69
71
 
70
- return `${katelloApi.getApiUrl('/packages/thindex')}?per_page=7&include_permissions=true&packages_restrict_upgradable=${selectedAction === 'upgrade'}`;
72
+ return `${katelloApi.getApiUrl(`/${contentTypeName}/thindex`)}?per_page=7&include_permissions=true&packages_restrict_upgradable=${selectedAction === 'upgrade'}`;
71
73
  };
72
74
 
73
75
  const BulkPackagesWizard = () => {
74
76
  const { modalOpen, setModalClosed: closeModal } = useForemanModal({ id: 'bulk-packages-wizard' });
75
77
 
76
-
77
78
  const [selectedAction, setSelectedAction] = useState(UPGRADE_ALL);
78
79
 
79
80
  const { selectedCount: initialSelectedHostCount, fetchBulkParams }
@@ -86,28 +87,32 @@ const BulkPackagesWizard = () => {
86
87
  const packageActionsNames = {
87
88
  install: __('Install packages'), remove: __('Remove packages'), upgrade: __('Upgrade packages'), upgradeAll: __('Upgrade packages'),
88
89
  };
89
- const packageActions = () => {
90
- switch (selectedAction) {
91
- case INSTALL:
92
- return (
93
- <BulkPackagesInstallTable modalIsOpen={modalOpen} />
94
- );
95
- case REMOVE:
96
- return (
97
- <BulkPackagesRemoveTable modalIsOpen={modalOpen} />
98
- );
99
- default:
100
- return (
101
- <BulkPackagesUpgradeTable modalIsOpen={modalOpen} />
102
- );
90
+
91
+
92
+ const initialSelectedHosts = fetchBulkParams();
93
+
94
+ const hostsBulkSelect =
95
+ useHostsBulkSelect({ initialSelectedHosts, modalIsOpen: modalOpen });
96
+
97
+ const currentlySelectedHosts =
98
+ hostsBulkSelect?.hostsResponse?.response?.results?.filter(host =>
99
+ !hostsBulkSelect.hostsBulkSelect.exclusionSet.has(host.id));
100
+
101
+ const getContentTypeName = () => {
102
+ if (currentlySelectedHosts === undefined) {
103
+ return PACKAGE_CONTENT_TYPE_NAMES.INVALID;
104
+ } else if (currentlySelectedHosts[0]?.operatingsystem_family === 'Debian') {
105
+ return PACKAGE_CONTENT_TYPE_NAMES.DEBIAN;
103
106
  }
107
+
108
+ return PACKAGE_CONTENT_TYPE_NAMES.REDHAT;
104
109
  };
105
110
 
106
111
  const finishButtonTextValues = {
107
112
  install: __('Install'), remove: __('Remove'), upgrade: __('Upgrade'), upgradeAll: __('Upgrade'),
108
113
  };
109
114
  const finishButtonText = finishButtonTextValues[selectedAction];
110
- const PACKAGES_URL = getPackagesUrl(selectedAction);
115
+ const PACKAGES_URL = getPackagesUrl(selectedAction, getContentTypeName());
111
116
  const apiOptions = { key: 'BULK_HOST_PACKAGES' };
112
117
  const replacementResponse = !modalOpen ? { response: {} } : false;
113
118
  const packagesResponse = useTableIndexAPIResponse({
@@ -132,11 +137,6 @@ const BulkPackagesWizard = () => {
132
137
  idColumn: 'name',
133
138
  });
134
139
 
135
- const initialSelectedHosts = fetchBulkParams();
136
-
137
- const hostsBulkSelect =
138
- useHostsBulkSelect({ initialSelectedHosts, modalIsOpen: modalOpen });
139
-
140
140
  // eslint-disable-next-line no-restricted-globals
141
141
  const selectionIsValid = count => count > 0 || isNaN(count);
142
142
  const packagesResultsPresent = packagesResults?.length > 0;
@@ -164,6 +164,33 @@ const BulkPackagesWizard = () => {
164
164
  packagesResponse,
165
165
  hostsBulkSelect: hostsBulkSelect.hostsBulkSelect,
166
166
  };
167
+
168
+ const packageActions = () => {
169
+ switch (selectedAction) {
170
+ case INSTALL:
171
+ return (
172
+ <BulkPackagesInstallTable
173
+ contentTypeName={getContentTypeName()}
174
+ modalIsOpen={modalOpen}
175
+ />
176
+ );
177
+ case REMOVE:
178
+ return (
179
+ <BulkPackagesRemoveTable
180
+ contentTypeName={getContentTypeName()}
181
+ modalIsOpen={modalOpen}
182
+ />
183
+ );
184
+ default:
185
+ return (
186
+ <BulkPackagesUpgradeTable
187
+ contentTypeName={getContentTypeName()}
188
+ modalIsOpen={modalOpen}
189
+ />
190
+ );
191
+ }
192
+ };
193
+
167
194
  return (
168
195
  <BulkPackagesWizardContext.Provider value={bulkPackagesWizardContextData}>
169
196
  <Wizard
@@ -86,6 +86,13 @@ const HostReview = ({
86
86
  isSorted: true,
87
87
  weight: 100,
88
88
  },
89
+ cv_environments: {
90
+ title: __('Content view environments'),
91
+ wrapper: hostDetails =>
92
+ hostDetails?.content_facet_attributes?.content_view_environment_labels,
93
+ isSorted: false,
94
+ weight: 100,
95
+ },
89
96
  };
90
97
 
91
98
  // restrict search query to only selected hosts
@@ -15,7 +15,9 @@ import ContentDetails from '../../scenes/Content/Details';
15
15
  import withHeader from './withHeaders';
16
16
  import ChangeContentSource from '../../scenes/Hosts/ChangeContentSource';
17
17
  import AlternateContentSource from '../../scenes/AlternateContentSources';
18
- import BootedContainerImages from '../../scenes/BootedContainerImages';
18
+ import BootedContainerImages from '../../scenes/ContainerImages/Booted';
19
+ import ContainerImages from '../../scenes/ContainerImages';
20
+ import ManifestDetails from '../../scenes/ContainerImages/Synced/Details';
19
21
  import FlatpakRemotes from '../../scenes/FlatpakRemotes';
20
22
  import FlatpakRemoteDetails from '../../scenes/FlatpakRemotes/Details';
21
23
 
@@ -92,6 +94,14 @@ export const links = [
92
94
  path: 'booted_container_images',
93
95
  component: WithOrganization(withHeader(BootedContainerImages, { title: __('Booted container images') })),
94
96
  },
97
+ {
98
+ path: 'labs/container_images',
99
+ component: WithOrganization(withHeader(ContainerImages, { title: __('Container Images') })),
100
+ },
101
+ {
102
+ path: 'labs/container_images/:id([0-9]+)',
103
+ component: WithOrganization(withHeader(ManifestDetails, { title: __('Manifest Details') })),
104
+ },
95
105
  {
96
106
  path: 'flatpak_remotes',
97
107
  component: WithOrganization(withHeader(FlatpakRemotes, { title: __('Flatpak Remotes') })),
@@ -34,6 +34,7 @@ import HostsIndexActionsBar from './components/extensions/Hosts/ActionsBar';
34
34
  import RecentCommunicationCardExtensions from './components/extensions/HostDetails/DetailsTabCards/RecentCommunicationCardExtensions';
35
35
  import SystemPurposeCard from './components/extensions/HostDetails/Cards/SystemPurposeCard/SystemPurposeCard';
36
36
  import BulkChangeHostCVModal from './components/extensions/Hosts/BulkActions/BulkChangeHostCVModal/index.js';
37
+ import BulkChangeHostCollectionsModal, { BulkChangeHostCollectionsMenuItem } from './components/extensions/Hosts/BulkActions/BulkChangeHostCollectionsModal/index.js';
37
38
  import BulkPackagesWizardModal from './components/extensions/Hosts/BulkActions/BulkPackagesWizard/index.js';
38
39
  import BulkErrataWizardModal from './components/extensions/Hosts/BulkActions/BulkErrataWizard/index.js';
39
40
  import BulkRepositorySetsWizardModal from './components/extensions/Hosts/BulkActions/BulkRepositorySetsWizard/index.js';
@@ -95,6 +96,8 @@ addGlobalFill('_all-hosts-modals', 'BulkChangeHostCVModal', <BulkChangeHostCVMod
95
96
  addGlobalFill('_all-hosts-modals', 'BulkPackagesWizardModal', <BulkPackagesWizardModal key="bulk-packages-wizard-modal" />, 200);
96
97
  addGlobalFill('_all-hosts-modals', 'BulkErrataWizardModal', <BulkErrataWizardModal key="bulk-errata-wizard-modal" />, 300);
97
98
  addGlobalFill('_all-hosts-modals', 'BulkRepositorySetsWizardModal', <BulkRepositorySetsWizardModal key="bulk-repo-sets-wizard-modal" />, 400);
99
+ addGlobalFill('_all-hosts-modals', 'BulkChangeHostCollectionsModal', <BulkChangeHostCollectionsModal key="bulk-change-host-collections-modal" />, 500);
100
+ addGlobalFill('_host-associations', 'BulkChangeHostCollectionsMenuItem', <BulkChangeHostCollectionsMenuItem key="bulk-change-host-collections-menu-item" />, 100);
98
101
 
99
102
  registerColumns(hostsIndexColumnExtensions);
100
103
  registerGetActions({
@@ -1,4 +1,4 @@
1
- import { foremanApi } from '../../services/api';
1
+ import { foremanApi } from '../../../services/api';
2
2
 
3
3
  const BOOTED_CONTAINER_IMAGES_KEY = 'BOOTED_CONTAINER_IMAGES';
4
4
  export const BOOTED_CONTAINER_IMAGES_API_PATH = foremanApi.getApiUrl('/hosts/bootc_images');
@@ -16,9 +16,10 @@ import {
16
16
  useTableSort,
17
17
  } from 'foremanReact/components/PF4/Helpers/useTableSort';
18
18
  import Pagination from 'foremanReact/components/Pagination';
19
- import EmptyPage from 'foremanReact/routes/common/EmptyPage';
20
19
  import { translate as __ } from 'foremanReact/common/I18n';
21
20
  import { useForemanHostsPageUrl } from 'foremanReact/Root/Context/ForemanContext';
21
+ import { STATUS } from '../containerImagesHelpers';
22
+ import TableEmptyState from '../TableEmptyState';
22
23
  import BOOTED_CONTAINER_IMAGES_KEY, { BOOTED_CONTAINER_IMAGES_API_PATH } from './BootedContainerImagesConstants';
23
24
 
24
25
  const BootedContainerImagesPage = () => {
@@ -79,11 +80,6 @@ const BootedContainerImagesPage = () => {
79
80
  });
80
81
  const expandedImages = useSet([]);
81
82
  const imageIsExpanded = bootcBootedImage => expandedImages.has(bootcBootedImage);
82
- const STATUS = {
83
- PENDING: 'PENDING',
84
- RESOLVED: 'RESOLVED',
85
- ERROR: 'ERROR',
86
- };
87
83
 
88
84
  const {
89
85
  response: {
@@ -108,7 +104,6 @@ const BootedContainerImagesPage = () => {
108
104
  <TableIndexPage
109
105
  apiUrl={BOOTED_CONTAINER_IMAGES_API_PATH}
110
106
  apiOptions={apiOptions}
111
- header={__('Booted container images')}
112
107
  createable={false}
113
108
  isDeleteable={false}
114
109
  controller="/katello/api/v2/host_bootc_images"
@@ -134,42 +129,11 @@ const BootedContainerImagesPage = () => {
134
129
  </>
135
130
  </Tr>
136
131
  </Thead>
137
- {(results.length === 0 || errorMessage) && (
138
- <Tbody>
139
- {status === STATUS.PENDING && results.length === 0 && (
140
- <Tr ouiaId="table-loading">
141
- <Td colSpan={100}>
142
- <EmptyPage
143
- message={{
144
- type: 'loading',
145
- text: __('Loading...'),
146
- }}
147
- />
148
- </Td>
149
- </Tr>
150
- )}
151
- {!(status === STATUS.PENDING) &&
152
- results.length === 0 &&
153
- !errorMessage && (
154
- <Tr ouiaId="table-empty">
155
- <Td colSpan={100}>
156
- <EmptyPage
157
- message={{
158
- type: 'empty',
159
- }}
160
- />
161
- </Td>
162
- </Tr>
163
- )}
164
- {errorMessage && (
165
- <Tr ouiaId="table-error">
166
- <Td colSpan={100}>
167
- <EmptyPage message={{ type: 'error', text: errorMessage }} />
168
- </Td>
169
- </Tr>
170
- )}
171
- </Tbody>
172
- )}
132
+ <TableEmptyState
133
+ status={status}
134
+ results={results}
135
+ errorMessage={errorMessage}
136
+ />
173
137
  {results?.map((result, rowIndex) => {
174
138
  const { bootc_booted_image: bootcBootedImage, digests } = result;
175
139
  const isExpanded = imageIsExpanded(bootcBootedImage);
@@ -1,6 +1,6 @@
1
1
  import React from 'react';
2
2
  import { renderWithRedux, patientlyWaitFor, act } from 'react-testing-lib-wrapper';
3
- import { nockInstance, assertNockRequest, mockAutocomplete } from '../../../test-utils/nockWrapper';
3
+ import { nockInstance, assertNockRequest, mockAutocomplete } from '../../../../test-utils/nockWrapper';
4
4
  import BootedContainerImagesPage from '../BootedContainerImagesPage';
5
5
  import bootcImagesData from './bootedContainerImages.fixtures';
6
6
 
@@ -0,0 +1,86 @@
1
+ import React, { useState } from 'react';
2
+ import { useHistory, useLocation } from 'react-router-dom';
3
+ import {
4
+ Title,
5
+ PageSection,
6
+ Stack,
7
+ StackItem,
8
+ Tabs,
9
+ Tab,
10
+ TabTitleText,
11
+ TabTitleIcon,
12
+ Popover,
13
+ Button,
14
+ } from '@patternfly/react-core';
15
+ import { SyncAltIcon, OutlinedQuestionCircleIcon } from '@patternfly/react-icons';
16
+ import { translate as __ } from 'foremanReact/common/I18n';
17
+ import FontAwesomeImageModeIcon from '../../components/extensions/Hosts/FontAwesomeImageModeIcon';
18
+ import BootedContainerImagesPage from './Booted/BootedContainerImagesPage';
19
+ import SyncedContainerImagesPage from './Synced/SyncedContainerImagesPage';
20
+
21
+ const ContainerImagesPage = () => {
22
+ const [activeTabKey, setActiveTabKey] = useState(0);
23
+ const history = useHistory();
24
+ const location = useLocation();
25
+
26
+ const handleTabClick = (event, tabIndex) => {
27
+ setActiveTabKey(tabIndex);
28
+ history.replace(location.pathname);
29
+ };
30
+
31
+ return (
32
+ <PageSection variant="light">
33
+ <Stack hasGutter>
34
+ <StackItem>
35
+ <Title headingLevel="h1" size="2xl" ouiaId="container-images-title">
36
+ {__('Container images')}
37
+ <Popover
38
+ headerContent={<div>{__('Container images')}</div>}
39
+ bodyContent={
40
+ <div>
41
+ {__('View container images in the local registry using the Synced tab. View container images booted by image mode hosts using the Booted tab. The Booted tab also shows images outside of the local container registry.')}
42
+ </div>
43
+ }
44
+ >
45
+ <Button variant="plain" aria-label="Help" isInline icon={<OutlinedQuestionCircleIcon size="sm" />} ouiaId="container-images-help-button" />
46
+ </Popover>
47
+ </Title>
48
+ </StackItem>
49
+ <StackItem>
50
+ <Tabs
51
+ activeKey={activeTabKey}
52
+ onSelect={handleTabClick}
53
+ ouiaId="container-images-tabs"
54
+ >
55
+ <Tab
56
+ eventKey={0}
57
+ title={
58
+ <>
59
+ <TabTitleIcon><SyncAltIcon /></TabTitleIcon>
60
+ <TabTitleText>{__('Synced')}</TabTitleText>
61
+ </>
62
+ }
63
+ ouiaId="container-images-synced-tab"
64
+ />
65
+ <Tab
66
+ eventKey={1}
67
+ title={
68
+ <>
69
+ <TabTitleIcon><FontAwesomeImageModeIcon /></TabTitleIcon>
70
+ <TabTitleText>{__('Booted')}</TabTitleText>
71
+ </>
72
+ }
73
+ ouiaId="container-images-booted-tab"
74
+ />
75
+ </Tabs>
76
+ </StackItem>
77
+ <StackItem>
78
+ {activeTabKey === 0 && <SyncedContainerImagesPage />}
79
+ {activeTabKey === 1 && <BootedContainerImagesPage />}
80
+ </StackItem>
81
+ </Stack>
82
+ </PageSection>
83
+ );
84
+ };
85
+
86
+ export default ContainerImagesPage;
@@ -0,0 +1,105 @@
1
+ import React, { useState } from 'react';
2
+ import PropTypes from 'prop-types';
3
+ import { translate as __ } from 'foremanReact/common/I18n';
4
+ import {
5
+ Modal,
6
+ ModalVariant,
7
+ Button,
8
+ Label,
9
+ Flex,
10
+ FlexItem,
11
+ } from '@patternfly/react-core';
12
+
13
+ const LabelsAnnotationsModal = ({
14
+ show, setIsOpen, digest, labels, annotations,
15
+ }) => {
16
+ const INITIAL_DISPLAY_COUNT = 10;
17
+ const [showAll, setShowAll] = useState(false);
18
+
19
+ const handleClose = () => {
20
+ setShowAll(false);
21
+ setIsOpen(false);
22
+ };
23
+
24
+ // Combine labels and annotations into a single array of key-value pairs
25
+ const allItems = [
26
+ ...Object.entries(labels || {}).map(([key, value]) => ({
27
+ key: `label-${key}`,
28
+ value: `${key}=${value}`,
29
+ })),
30
+ ...Object.entries(annotations || {}).map(([key, value]) => ({
31
+ key: `annotation-${key}`,
32
+ value: `${key}=${value}`,
33
+ })),
34
+ ];
35
+
36
+ const totalCount = allItems.length;
37
+ const displayedItems = showAll ? allItems : allItems.slice(0, INITIAL_DISPLAY_COUNT);
38
+ const remainingCount = totalCount - INITIAL_DISPLAY_COUNT;
39
+
40
+ return (
41
+ <Modal
42
+ ouiaId="labels-annotations-modal"
43
+ title={__('Labels and annotations')}
44
+ variant={ModalVariant.medium}
45
+ isOpen={show}
46
+ onClose={handleClose}
47
+ appendTo={document.body}
48
+ actions={[
49
+ <Button key="close" variant="link" onClick={handleClose} ouiaId="labels-annotations-close-button">
50
+ {__('Close')}
51
+ </Button>,
52
+ ]}
53
+ >
54
+ <div>
55
+ <p>
56
+ {__('View labels and annotations for image ')}
57
+ <strong>{digest}</strong>.
58
+ </p>
59
+ <p style={{ marginTop: '16px', fontWeight: 'bold' }}>
60
+ {__(`${totalCount} labels and annotations`)}
61
+ </p>
62
+ <Flex
63
+ spaceItems={{ default: 'spaceItemsSm' }}
64
+ style={{ marginTop: '16px' }}
65
+ direction={{ default: 'row' }}
66
+ flexWrap={{ default: 'wrap' }}
67
+ >
68
+ {displayedItems.map(item => (
69
+ <FlexItem key={item.key}>
70
+ <Label>{item.value}</Label>
71
+ </FlexItem>
72
+ ))}
73
+ </Flex>
74
+ {!showAll && remainingCount > 0 && (
75
+ <Button
76
+ variant="link"
77
+ isInline
78
+ onClick={() => setShowAll(true)}
79
+ style={{ marginTop: '16px', padding: 0 }}
80
+ ouiaId="show-more-labels-annotations-button"
81
+ >
82
+ {__(`Show ${remainingCount} more`)}
83
+ </Button>
84
+ )}
85
+ </div>
86
+ </Modal>
87
+ );
88
+ };
89
+
90
+ LabelsAnnotationsModal.propTypes = {
91
+ show: PropTypes.bool,
92
+ setIsOpen: PropTypes.func.isRequired,
93
+ digest: PropTypes.string,
94
+ labels: PropTypes.objectOf(PropTypes.string),
95
+ annotations: PropTypes.objectOf(PropTypes.string),
96
+ };
97
+
98
+ LabelsAnnotationsModal.defaultProps = {
99
+ show: false,
100
+ digest: '',
101
+ labels: {},
102
+ annotations: {},
103
+ };
104
+
105
+ export default LabelsAnnotationsModal;