katello 4.18.0 → 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 (345) hide show
  1. checksums.yaml +4 -4
  2. data/app/assets/javascripts/katello/locale/bn/katello.js +52 -349
  3. data/app/assets/javascripts/katello/locale/bn_IN/katello.js +52 -349
  4. data/app/assets/javascripts/katello/locale/ca/katello.js +52 -349
  5. data/app/assets/javascripts/katello/locale/cs/katello.js +53 -350
  6. data/app/assets/javascripts/katello/locale/cs_CZ/katello.js +54 -351
  7. data/app/assets/javascripts/katello/locale/de/katello.js +56 -353
  8. data/app/assets/javascripts/katello/locale/de_AT/katello.js +52 -349
  9. data/app/assets/javascripts/katello/locale/de_DE/katello.js +52 -349
  10. data/app/assets/javascripts/katello/locale/el/katello.js +54 -351
  11. data/app/assets/javascripts/katello/locale/en/katello.js +53 -350
  12. data/app/assets/javascripts/katello/locale/en_GB/katello.js +53 -350
  13. data/app/assets/javascripts/katello/locale/en_US/katello.js +52 -349
  14. data/app/assets/javascripts/katello/locale/es/katello.js +56 -353
  15. data/app/assets/javascripts/katello/locale/et_EE/katello.js +52 -349
  16. data/app/assets/javascripts/katello/locale/fr/katello.js +138 -435
  17. data/app/assets/javascripts/katello/locale/gl/katello.js +52 -349
  18. data/app/assets/javascripts/katello/locale/gu/katello.js +52 -349
  19. data/app/assets/javascripts/katello/locale/he_IL/katello.js +52 -349
  20. data/app/assets/javascripts/katello/locale/hi/katello.js +52 -349
  21. data/app/assets/javascripts/katello/locale/id/katello.js +52 -349
  22. data/app/assets/javascripts/katello/locale/it/katello.js +53 -350
  23. data/app/assets/javascripts/katello/locale/ja/katello.js +142 -439
  24. data/app/assets/javascripts/katello/locale/ka/katello.js +56 -353
  25. data/app/assets/javascripts/katello/locale/kn/katello.js +52 -349
  26. data/app/assets/javascripts/katello/locale/ko/katello.js +135 -432
  27. data/app/assets/javascripts/katello/locale/ml_IN/katello.js +52 -349
  28. data/app/assets/javascripts/katello/locale/mr/katello.js +52 -349
  29. data/app/assets/javascripts/katello/locale/nl_NL/katello.js +52 -349
  30. data/app/assets/javascripts/katello/locale/or/katello.js +52 -349
  31. data/app/assets/javascripts/katello/locale/pa/katello.js +52 -349
  32. data/app/assets/javascripts/katello/locale/pl/katello.js +52 -349
  33. data/app/assets/javascripts/katello/locale/pl_PL/katello.js +52 -349
  34. data/app/assets/javascripts/katello/locale/pt/katello.js +52 -349
  35. data/app/assets/javascripts/katello/locale/pt_BR/katello.js +56 -353
  36. data/app/assets/javascripts/katello/locale/ro/katello.js +52 -349
  37. data/app/assets/javascripts/katello/locale/ro_RO/katello.js +52 -349
  38. data/app/assets/javascripts/katello/locale/ru/katello.js +54 -351
  39. data/app/assets/javascripts/katello/locale/sl/katello.js +52 -349
  40. data/app/assets/javascripts/katello/locale/sv_SE/katello.js +52 -349
  41. data/app/assets/javascripts/katello/locale/ta/katello.js +52 -349
  42. data/app/assets/javascripts/katello/locale/ta_IN/katello.js +52 -349
  43. data/app/assets/javascripts/katello/locale/te/katello.js +52 -349
  44. data/app/assets/javascripts/katello/locale/tr/katello.js +52 -349
  45. data/app/assets/javascripts/katello/locale/vi/katello.js +52 -349
  46. data/app/assets/javascripts/katello/locale/vi_VN/katello.js +52 -349
  47. data/app/assets/javascripts/katello/locale/zh/katello.js +52 -349
  48. data/app/assets/javascripts/katello/locale/zh_CN/katello.js +135 -432
  49. data/app/assets/javascripts/katello/locale/zh_TW/katello.js +54 -351
  50. data/app/controllers/katello/api/registry/registry_proxies_controller.rb +46 -13
  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_export_incrementals_controller.rb +56 -34
  54. data/app/controllers/katello/api/v2/content_view_filter_rules_controller.rb +1 -1
  55. data/app/controllers/katello/api/v2/content_views_controller.rb +18 -3
  56. data/app/controllers/katello/api/v2/debs_controller.rb +21 -11
  57. data/app/controllers/katello/api/v2/docker_tags_controller.rb +7 -0
  58. data/app/controllers/katello/api/v2/errata_controller.rb +4 -4
  59. data/app/controllers/katello/api/v2/flatpak_remote_repositories_controller.rb +21 -19
  60. data/app/controllers/katello/api/v2/host_debs_controller.rb +16 -1
  61. data/app/controllers/katello/api/v2/host_subscriptions_controller.rb +3 -60
  62. data/app/controllers/katello/api/v2/hosts_bulk_actions_controller.rb +10 -53
  63. data/app/controllers/katello/api/v2/repositories_controller.rb +0 -1
  64. data/app/controllers/katello/concerns/organizations_controller_extensions.rb +3 -0
  65. data/app/lib/actions/candlepin/activation_key/create.rb +0 -2
  66. data/app/lib/actions/candlepin/activation_key/update.rb +0 -2
  67. data/app/lib/actions/candlepin/product/content_create.rb +3 -5
  68. data/app/lib/actions/candlepin/product/content_update.rb +2 -3
  69. data/app/lib/actions/helpers/rolling_cv_repos.rb +1 -1
  70. data/app/lib/actions/katello/activation_key/create.rb +0 -1
  71. data/app/lib/actions/katello/activation_key/update.rb +0 -2
  72. data/app/lib/actions/katello/capsule_content/sync_capsule.rb +1 -6
  73. data/app/lib/actions/katello/content_credential/update.rb +1 -1
  74. data/app/lib/actions/katello/content_view/add_rolling_repo_clone.rb +18 -24
  75. data/app/lib/actions/katello/content_view/create.rb +9 -4
  76. data/app/lib/actions/katello/content_view/publish.rb +7 -7
  77. data/app/lib/actions/katello/content_view/refresh_rolling_repo.rb +6 -1
  78. data/app/lib/actions/katello/content_view/remove_rolling_repo_clone.rb +16 -11
  79. data/app/lib/actions/katello/content_view/update.rb +34 -7
  80. data/app/lib/actions/katello/product/content_create.rb +2 -2
  81. data/app/lib/actions/katello/product/content_destroy.rb +1 -1
  82. data/app/lib/actions/katello/repository/check_matching_content.rb +1 -1
  83. data/app/lib/actions/katello/repository/clone_contents.rb +1 -1
  84. data/app/lib/actions/katello/repository/create.rb +1 -1
  85. data/app/lib/actions/katello/repository/destroy.rb +4 -4
  86. data/app/lib/actions/katello/repository/finish_upload.rb +1 -1
  87. data/app/lib/actions/katello/repository/sync.rb +1 -1
  88. data/app/lib/actions/pulp3/orchestration/repository/copy_all_units.rb +2 -2
  89. data/app/lib/actions/pulp3/orchestration/repository/generate_metadata.rb +1 -1
  90. data/app/lib/actions/pulp3/orchestration/repository/multi_copy_all_units.rb +1 -1
  91. data/app/lib/actions/pulp3/repository/save_publication.rb +3 -1
  92. data/app/lib/actions/pulp3/repository/save_version.rb +45 -24
  93. data/app/lib/actions/pulp3/repository/save_versions.rb +2 -1
  94. data/app/lib/katello/resources/candlepin/activation_key.rb +3 -4
  95. data/app/lib/katello/resources/candlepin/upstream_job.rb +9 -1
  96. data/app/lib/katello/resources/candlepin.rb +4 -0
  97. data/app/models/katello/authorization/repository.rb +17 -4
  98. data/app/models/katello/concerns/subscription_facet_host_extensions.rb +0 -7
  99. data/app/models/katello/content_view_deb_filter.rb +10 -0
  100. data/app/models/katello/content_view_deb_filter_rule.rb +7 -0
  101. data/app/models/katello/deb.rb +10 -12
  102. data/app/models/katello/erratum.rb +1 -1
  103. data/app/models/katello/glue/provider.rb +14 -3
  104. data/app/models/katello/host/content_facet.rb +1 -1
  105. data/app/models/katello/host/subscription_facet.rb +1 -7
  106. data/app/models/katello/product_content.rb +2 -2
  107. data/app/models/katello/repository.rb +4 -23
  108. data/app/models/katello/root_repository.rb +2 -5
  109. data/app/services/katello/candlepin/event_handler.rb +0 -33
  110. data/app/services/katello/candlepin/message_handler.rb +0 -41
  111. data/app/services/katello/content_unit_indexer.rb +59 -13
  112. data/app/services/katello/product_content_finder.rb +16 -7
  113. data/app/services/katello/pulp3/alternate_content_source.rb +2 -2
  114. data/app/services/katello/pulp3/ansible_collection.rb +1 -0
  115. data/app/services/katello/pulp3/api/content_guard.rb +5 -5
  116. data/app/services/katello/pulp3/api/core.rb +10 -0
  117. data/app/services/katello/pulp3/content_view_version/export.rb +25 -10
  118. data/app/services/katello/pulp3/deb.rb +1 -0
  119. data/app/services/katello/pulp3/docker_manifest.rb +1 -0
  120. data/app/services/katello/pulp3/docker_manifest_list.rb +1 -0
  121. data/app/services/katello/pulp3/docker_tag.rb +1 -0
  122. data/app/services/katello/pulp3/file_unit.rb +1 -0
  123. data/app/services/katello/pulp3/generic_content_unit.rb +1 -0
  124. data/app/services/katello/pulp3/module_stream.rb +1 -0
  125. data/app/services/katello/pulp3/package_group.rb +1 -0
  126. data/app/services/katello/pulp3/repository/apt.rb +30 -13
  127. data/app/services/katello/pulp3/repository.rb +59 -10
  128. data/app/services/katello/pulp3/rpm.rb +3 -2
  129. data/app/services/katello/pulp3/srpm.rb +3 -2
  130. data/app/services/katello/pulp3/task_group.rb +1 -1
  131. data/app/services/katello/registration_manager.rb +19 -17
  132. data/app/services/katello/repository_type_manager.rb +7 -5
  133. data/app/services/katello/smart_proxy_helper.rb +1 -6
  134. data/app/views/foreman/job_templates/upload_profile.erb +5 -0
  135. data/app/views/katello/api/v2/activation_keys/base.json.rabl +1 -1
  136. data/app/views/katello/api/v2/content_views/base.json.rabl +1 -0
  137. data/app/views/katello/api/v2/debs/thindex.json.rabl +6 -0
  138. data/app/views/katello/api/v2/docker_tags/_base.json.rabl +32 -0
  139. data/app/views/katello/api/v2/docker_tags/show.json.rabl +0 -5
  140. data/app/views/katello/api/v2/flatpak_remotes/index.json.rabl +6 -0
  141. data/app/views/katello/api/v2/host_debs/installed_debs.json.rabl +6 -0
  142. data/app/views/katello/api/v2/hosts_bulk_actions/applicable_errata.json.rabl +1 -1
  143. data/app/views/katello/api/v2/hosts_bulk_actions/applicable_erratum.json.rabl +9 -0
  144. data/app/views/katello/api/v2/hosts_bulk_actions/installable_errata.json.rabl +1 -1
  145. data/app/views/katello/api/v2/hosts_bulk_actions/{erratum.json.rabl → installable_erratum.json.rabl} +3 -3
  146. data/app/views/katello/api/v2/subscription_facet/base.json.rabl +1 -1
  147. data/config/initializers/monkeys.rb +1 -0
  148. data/config/routes/api/v2.rb +2 -2
  149. data/config/routes/overrides.rb +2 -7
  150. data/config/routes.rb +2 -0
  151. data/db/migrate/20211019192121_create_cdn_configuration.katello.rb +1 -1
  152. data/db/migrate/20250912000000_add_pulp_prn_fields.rb +73 -0
  153. data/db/migrate/20250912000001_populate_pulp_prn_fields.rb +403 -0
  154. data/db/migrate/20251009142516_remove_auto_attach_from_activation_keys.rb +5 -0
  155. data/db/migrate/20251009142517_remove_autoheal_from_subscription_facets.rb +5 -0
  156. data/db/seeds.d/111-upgrade_tasks.rb +2 -0
  157. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/i18n/locale/el.po +2 -2
  158. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/i18n/locale/fr.po +6 -1
  159. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/i18n/locale/ja.po +5 -2
  160. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/i18n/locale/ko.po +5 -2
  161. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/i18n/locale/zh_CN.po +5 -2
  162. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/i18n/translations.js +4 -4
  163. data/lib/katello/permission_creator.rb +2 -2
  164. data/lib/katello/permissions/host_permissions.rb +0 -6
  165. data/lib/katello/plugin.rb +16 -8
  166. data/lib/katello/tasks/jenkins.rake +1 -1
  167. data/lib/katello/tasks/upgrades/4.19/enable_structured_apt_for_deb.rake +87 -0
  168. data/lib/katello/tasks/upgrades/4.19/populate_repository_version_prns.rake +32 -0
  169. data/lib/katello/version.rb +1 -1
  170. data/lib/monkeys/fix_rpm_repository_gpgcheck.rb +38 -0
  171. data/locale/bn/LC_MESSAGES/katello.mo +0 -0
  172. data/locale/bn/katello.po +52 -349
  173. data/locale/bn_IN/LC_MESSAGES/katello.mo +0 -0
  174. data/locale/bn_IN/katello.po +52 -349
  175. data/locale/ca/LC_MESSAGES/katello.mo +0 -0
  176. data/locale/ca/katello.po +52 -349
  177. data/locale/cs/LC_MESSAGES/katello.mo +0 -0
  178. data/locale/cs/katello.po +54 -350
  179. data/locale/cs_CZ/LC_MESSAGES/katello.mo +0 -0
  180. data/locale/cs_CZ/katello.po +54 -351
  181. data/locale/de/LC_MESSAGES/katello.mo +0 -0
  182. data/locale/de/katello.po +56 -353
  183. data/locale/de_AT/LC_MESSAGES/katello.mo +0 -0
  184. data/locale/de_AT/katello.po +52 -349
  185. data/locale/de_DE/LC_MESSAGES/katello.mo +0 -0
  186. data/locale/de_DE/katello.po +52 -349
  187. data/locale/el/LC_MESSAGES/katello.mo +0 -0
  188. data/locale/el/katello.po +55 -352
  189. data/locale/en/LC_MESSAGES/katello.mo +0 -0
  190. data/locale/en/katello.po +54 -350
  191. data/locale/en_GB/LC_MESSAGES/katello.mo +0 -0
  192. data/locale/en_GB/katello.po +53 -350
  193. data/locale/en_US/LC_MESSAGES/katello.mo +0 -0
  194. data/locale/en_US/katello.po +52 -349
  195. data/locale/es/LC_MESSAGES/katello.mo +0 -0
  196. data/locale/es/katello.po +56 -353
  197. data/locale/et_EE/LC_MESSAGES/katello.mo +0 -0
  198. data/locale/et_EE/katello.po +52 -349
  199. data/locale/fr/LC_MESSAGES/katello.mo +0 -0
  200. data/locale/fr/katello.po +139 -435
  201. data/locale/gl/LC_MESSAGES/katello.mo +0 -0
  202. data/locale/gl/katello.po +52 -349
  203. data/locale/gu/LC_MESSAGES/katello.mo +0 -0
  204. data/locale/gu/katello.po +52 -349
  205. data/locale/he_IL/LC_MESSAGES/katello.mo +0 -0
  206. data/locale/he_IL/katello.po +52 -349
  207. data/locale/hi/LC_MESSAGES/katello.mo +0 -0
  208. data/locale/hi/katello.po +52 -349
  209. data/locale/id/LC_MESSAGES/katello.mo +0 -0
  210. data/locale/id/katello.po +52 -349
  211. data/locale/it/LC_MESSAGES/katello.mo +0 -0
  212. data/locale/it/katello.po +53 -350
  213. data/locale/ja/LC_MESSAGES/katello.mo +0 -0
  214. data/locale/ja/katello.po +143 -439
  215. data/locale/ka/LC_MESSAGES/katello.mo +0 -0
  216. data/locale/ka/katello.po +56 -353
  217. data/locale/katello.pot +695 -1152
  218. data/locale/kn/LC_MESSAGES/katello.mo +0 -0
  219. data/locale/kn/katello.po +52 -349
  220. data/locale/ko/LC_MESSAGES/katello.mo +0 -0
  221. data/locale/ko/katello.po +136 -432
  222. data/locale/ml_IN/LC_MESSAGES/katello.mo +0 -0
  223. data/locale/ml_IN/katello.po +52 -349
  224. data/locale/mr/LC_MESSAGES/katello.mo +0 -0
  225. data/locale/mr/katello.po +52 -349
  226. data/locale/nl_NL/LC_MESSAGES/katello.mo +0 -0
  227. data/locale/nl_NL/katello.po +52 -349
  228. data/locale/or/LC_MESSAGES/katello.mo +0 -0
  229. data/locale/or/katello.po +52 -349
  230. data/locale/pa/LC_MESSAGES/katello.mo +0 -0
  231. data/locale/pa/katello.po +52 -349
  232. data/locale/pl/LC_MESSAGES/katello.mo +0 -0
  233. data/locale/pl/katello.po +52 -349
  234. data/locale/pl_PL/LC_MESSAGES/katello.mo +0 -0
  235. data/locale/pl_PL/katello.po +52 -349
  236. data/locale/pt/LC_MESSAGES/katello.mo +0 -0
  237. data/locale/pt/katello.po +52 -349
  238. data/locale/pt_BR/LC_MESSAGES/katello.mo +0 -0
  239. data/locale/pt_BR/katello.po +56 -353
  240. data/locale/ro/LC_MESSAGES/katello.mo +0 -0
  241. data/locale/ro/katello.po +52 -349
  242. data/locale/ro_RO/LC_MESSAGES/katello.mo +0 -0
  243. data/locale/ro_RO/katello.po +52 -349
  244. data/locale/ru/LC_MESSAGES/katello.mo +0 -0
  245. data/locale/ru/katello.po +54 -351
  246. data/locale/sl/LC_MESSAGES/katello.mo +0 -0
  247. data/locale/sl/katello.po +52 -349
  248. data/locale/sv_SE/LC_MESSAGES/katello.mo +0 -0
  249. data/locale/sv_SE/katello.po +52 -349
  250. data/locale/ta/LC_MESSAGES/katello.mo +0 -0
  251. data/locale/ta/katello.po +52 -349
  252. data/locale/ta_IN/LC_MESSAGES/katello.mo +0 -0
  253. data/locale/ta_IN/katello.po +52 -349
  254. data/locale/te/LC_MESSAGES/katello.mo +0 -0
  255. data/locale/te/katello.po +52 -349
  256. data/locale/tr/LC_MESSAGES/katello.mo +0 -0
  257. data/locale/tr/katello.po +52 -349
  258. data/locale/vi/LC_MESSAGES/katello.mo +0 -0
  259. data/locale/vi/katello.po +52 -349
  260. data/locale/vi_VN/LC_MESSAGES/katello.mo +0 -0
  261. data/locale/vi_VN/katello.po +52 -349
  262. data/locale/zh/LC_MESSAGES/katello.mo +0 -0
  263. data/locale/zh/katello.po +52 -349
  264. data/locale/zh_CN/LC_MESSAGES/katello.mo +0 -0
  265. data/locale/zh_CN/katello.po +136 -432
  266. data/locale/zh_TW/LC_MESSAGES/katello.mo +0 -0
  267. data/locale/zh_TW/katello.po +54 -351
  268. data/webpack/components/Content/Details/__tests__/__snapshots__/ContentDetails.test.js.snap +2 -2
  269. data/webpack/components/extensions/HostDetails/Cards/SystemPurposeCard/SystemPurposeEditModal.js +0 -2
  270. data/webpack/components/extensions/HostDetails/Cards/SystemPurposeCard/__tests__/SystemPurposeEditModal.test.js +0 -2
  271. data/webpack/components/extensions/Hosts/ActionsBar/index.js +1 -0
  272. data/webpack/components/extensions/Hosts/BulkActions/BulkActionsConstants.js +7 -0
  273. data/webpack/components/extensions/Hosts/BulkActions/BulkChangeHostCollectionsModal/BulkChangeHostCollectionsModal.js +388 -0
  274. data/webpack/components/extensions/Hosts/BulkActions/BulkChangeHostCollectionsModal/__tests__/BulkChangeHostCollectionsModal.test.js +640 -0
  275. data/webpack/components/extensions/Hosts/BulkActions/BulkChangeHostCollectionsModal/actions.js +28 -0
  276. data/webpack/components/extensions/Hosts/BulkActions/BulkChangeHostCollectionsModal/index.js +71 -0
  277. data/webpack/components/extensions/Hosts/BulkActions/BulkErrataWizard/BulkErrataWizard.js +1 -1
  278. data/webpack/components/extensions/Hosts/BulkActions/BulkPackagesWizard/02_BulkPackagesTable.js +10 -3
  279. data/webpack/components/extensions/Hosts/BulkActions/BulkPackagesWizard/BulkPackagesWizard.js +51 -24
  280. data/webpack/components/extensions/Hosts/BulkActions/HostReview.js +7 -0
  281. data/webpack/containers/Application/config.js +11 -1
  282. data/webpack/global_index.js +3 -0
  283. data/webpack/scenes/{BootedContainerImages → ContainerImages/Booted}/BootedContainerImagesConstants.js +1 -1
  284. data/webpack/scenes/{BootedContainerImages → ContainerImages/Booted}/BootedContainerImagesPage.js +7 -43
  285. data/webpack/scenes/{BootedContainerImages → ContainerImages/Booted}/__tests__/bootedContainerImagesPage.test.js +1 -1
  286. data/webpack/scenes/ContainerImages/ContainerImagesPage.js +86 -0
  287. data/webpack/scenes/ContainerImages/LabelsAnnotationsModal.js +105 -0
  288. data/webpack/scenes/ContainerImages/Synced/Details/ManifestDetails.js +218 -0
  289. data/webpack/scenes/ContainerImages/Synced/Details/ManifestDetailsActions.js +15 -0
  290. data/webpack/scenes/ContainerImages/Synced/Details/ManifestDetailsSelectors.js +16 -0
  291. data/webpack/scenes/ContainerImages/Synced/Details/__tests__/ManifestDetails.test.js +395 -0
  292. data/webpack/scenes/ContainerImages/Synced/Details/__tests__/manifestDetails.fixtures.json +43 -0
  293. data/webpack/scenes/ContainerImages/Synced/Details/__tests__/manifestList.fixtures.json +58 -0
  294. data/webpack/scenes/ContainerImages/Synced/Details/index.js +4 -0
  295. data/webpack/scenes/ContainerImages/Synced/SyncedContainerImagesPage.js +359 -0
  296. data/webpack/scenes/ContainerImages/Synced/SyncedContainerImagesPage.scss +21 -0
  297. data/webpack/scenes/ContainerImages/Synced/__tests__/LabelsAnnotationsModal.test.js +69 -0
  298. data/webpack/scenes/ContainerImages/Synced/__tests__/SyncedContainerImagesPage.test.js +335 -0
  299. data/webpack/scenes/ContainerImages/Synced/__tests__/syncedContainerImages.fixtures.json +105 -0
  300. data/webpack/scenes/ContainerImages/TableEmptyState.js +67 -0
  301. data/webpack/scenes/ContainerImages/containerImagesHelpers.js +48 -0
  302. data/webpack/scenes/ContainerImages/index.js +4 -0
  303. data/webpack/scenes/ContentViews/Create/CreateContentViewForm.js +29 -3
  304. data/webpack/scenes/ContentViews/Create/__tests__/contentViewCreateResult.fixtures.json +1 -0
  305. data/webpack/scenes/ContentViews/Create/__tests__/createContentView.test.js +45 -1
  306. data/webpack/scenes/ContentViews/Delete/__tests__/affectedHosts.fixtures.json +0 -1
  307. data/webpack/scenes/ContentViews/Details/ContentViewInfo.js +59 -1
  308. data/webpack/scenes/ContentViews/Details/Filters/CVDebFilterContent.js +1 -0
  309. data/webpack/scenes/ContentViews/Details/Filters/Rules/DebPackage/AddEditDebPackageRuleModal.js +164 -24
  310. data/webpack/scenes/ContentViews/Details/Filters/__tests__/CVDebFilterContent.test.js +268 -0
  311. data/webpack/scenes/ContentViews/Details/Filters/__tests__/cvDebFilterDetail.fixtures.json +95 -0
  312. data/webpack/scenes/ContentViews/Details/Filters/__tests__/cvDebFilterRules.fixtures.json +31 -0
  313. data/webpack/scenes/ContentViews/Details/Filters/__tests__/emptyCVDebFilterRules.fixtures.json +10 -0
  314. data/webpack/scenes/ContentViews/Details/Versions/BulkDelete/__tests__/hosts.fixtures.json +0 -1
  315. data/webpack/scenes/ContentViews/Details/Versions/Delete/__tests__/cvAffectedHosts.fixture.json +0 -1
  316. data/webpack/scenes/ContentViews/Details/__tests__/contentViewRollingDetail.test.js +15 -0
  317. data/webpack/scenes/ContentViews/Details/__tests__/contentViewRollingDetails.fixtures.json +1 -0
  318. data/webpack/scenes/ContentViews/__tests__/contentViewPage.test.js +9 -0
  319. data/webpack/scenes/FlatpakRemotes/CreateEdit/CreateFlatpakRemoteModal.js +5 -3
  320. data/webpack/scenes/FlatpakRemotes/CreateEdit/EditFlatpakRemotesModal.js +1 -1
  321. data/webpack/scenes/FlatpakRemotes/CreateEdit/FlatpakRemoteform.js +35 -3
  322. data/webpack/scenes/FlatpakRemotes/Details/FlatpakRemoteDetails.js +1 -1
  323. data/webpack/scenes/FlatpakRemotes/Details/RemoteRepositories/RemoteRepositoriesTable.css +3 -0
  324. data/webpack/scenes/FlatpakRemotes/Details/RemoteRepositories/RemoteRepositoriesTable.js +63 -132
  325. data/webpack/scenes/FlatpakRemotes/FlatpakRemotesPage.js +67 -143
  326. data/webpack/scenes/SmartProxy/ExpandableCvDetails.js +10 -2
  327. data/webpack/scenes/SmartProxy/SmartProxyContentActions.js +13 -2
  328. data/webpack/scenes/SmartProxy/SmartProxyContentConstants.js +1 -0
  329. data/webpack/scenes/SmartProxy/SmartProxyExpandableTable.js +8 -2
  330. data/webpack/scenes/SmartProxy/__tests__/SmartProxyContentTest.js +67 -1
  331. data/webpack/scenes/Subscriptions/Details/__tests__/__snapshots__/SubscriptionDetails.test.js.snap +2 -2
  332. data/webpack/scenes/Subscriptions/SubscriptionConstants.js +0 -2
  333. data/webpack/scenes/Subscriptions/__tests__/__snapshots__/SubscriptionsActions.test.js.snap +2 -2
  334. metadata +83 -55
  335. data/app/lib/actions/katello/host/attach_subscriptions.rb +0 -59
  336. data/app/lib/actions/katello/host/auto_attach_subscriptions.rb +0 -22
  337. data/app/lib/actions/katello/host/remove_subscriptions.rb +0 -50
  338. data/app/lib/actions/katello/organization/simple_content_access/disable.rb +0 -25
  339. data/app/lib/actions/katello/organization/simple_content_access/enable.rb +0 -25
  340. data/app/lib/actions/katello/organization/simple_content_access/toggle.rb +0 -42
  341. data/lib/katello/tasks/migrate_structure_content_for_deb.rake +0 -105
  342. data/lib/katello/tasks/upgrades/4.2/remove_checksum_values.rake +0 -17
  343. data/locale/action_names.rb +0 -186
  344. /data/webpack/scenes/{BootedContainerImages → ContainerImages/Booted}/__tests__/bootedContainerImages.fixtures.js +0 -0
  345. /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;