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,218 @@
1
+ import React, { useEffect } from 'react';
2
+ import { useParams, useHistory, useLocation } from 'react-router-dom';
3
+ import { useSelector, useDispatch, shallowEqual } from 'react-redux';
4
+ import {
5
+ Breadcrumb,
6
+ BreadcrumbItem,
7
+ Title,
8
+ PageSection,
9
+ Grid,
10
+ GridItem,
11
+ TextContent,
12
+ Text,
13
+ TextVariants,
14
+ ClipboardCopy,
15
+ Label,
16
+ Flex,
17
+ FlexItem,
18
+ } from '@patternfly/react-core';
19
+ import { translate as __ } from 'foremanReact/common/I18n';
20
+ import { STATUS } from 'foremanReact/constants';
21
+ import Loading from 'foremanReact/components/Loading';
22
+ import LongDateTime from 'foremanReact/components/common/dates/LongDateTime';
23
+ import EmptyStateMessage from '../../../../components/Table/EmptyStateMessage';
24
+ import {
25
+ getManifest,
26
+ getShortDigest,
27
+ formatManifestType,
28
+ } from '../../containerImagesHelpers';
29
+ import getDockerTagDetails from './ManifestDetailsActions';
30
+ import {
31
+ selectDockerTagDetails,
32
+ selectDockerTagDetailStatus,
33
+ selectDockerTagDetailError,
34
+ } from './ManifestDetailsSelectors';
35
+
36
+ const ManifestDetails = () => {
37
+ const { id } = useParams();
38
+ const tagId = Number(id);
39
+ const history = useHistory();
40
+ const location = useLocation();
41
+ const dispatch = useDispatch();
42
+
43
+ const searchParams = new URLSearchParams(location.search);
44
+ const manifestId = searchParams.get('manifest');
45
+
46
+ useEffect(() => {
47
+ dispatch(getDockerTagDetails(tagId));
48
+ }, [dispatch, tagId]);
49
+
50
+ const manifestData = useSelector(state =>
51
+ selectDockerTagDetails(state, tagId), shallowEqual) || {};
52
+ const status = useSelector(state =>
53
+ selectDockerTagDetailStatus(state, tagId));
54
+ const error = useSelector(state =>
55
+ selectDockerTagDetailError(state, tagId));
56
+
57
+ const getDisplayManifest = () => {
58
+ const parentManifest = getManifest(manifestData);
59
+
60
+ if (!manifestId || !parentManifest) {
61
+ return parentManifest;
62
+ }
63
+
64
+ if (parentManifest.manifest_type === 'list' && parentManifest.manifests) {
65
+ const childManifestId = parseInt(manifestId, 10);
66
+ return parentManifest.manifests.find(m => m.id === childManifestId);
67
+ }
68
+
69
+ return parentManifest;
70
+ };
71
+
72
+ if (status === STATUS.PENDING) {
73
+ return <Loading />;
74
+ }
75
+
76
+ if (status === STATUS.ERROR) {
77
+ return <EmptyStateMessage error={error} />;
78
+ }
79
+
80
+ const manifest = getDisplayManifest();
81
+ const digest = manifest?.digest || 'N/A';
82
+ const shortDigest = getShortDigest(digest);
83
+ const manifestType = formatManifestType(manifest);
84
+
85
+ // Filter to show only library repositories
86
+ const libraryRepositories = manifestData.repositories?.filter(repo =>
87
+ repo.library_instance) || [];
88
+
89
+ const labels = manifest?.labels || {};
90
+ const labelKeys = Object.keys(labels);
91
+
92
+ return (
93
+ <PageSection variant="light">
94
+ <Grid hasGutter span={12}>
95
+ <GridItem span={12}>
96
+ <Breadcrumb ouiaId="manifest-details-breadcrumb">
97
+ <BreadcrumbItem
98
+ to="/labs/container_images"
99
+ onClick={(e) => {
100
+ e.preventDefault();
101
+ history.push('/labs/container_images');
102
+ }}
103
+ >
104
+ {__('Container images')}
105
+ </BreadcrumbItem>
106
+ <BreadcrumbItem isActive>{shortDigest}</BreadcrumbItem>
107
+ </Breadcrumb>
108
+ </GridItem>
109
+
110
+ <GridItem span={12}>
111
+ <Title headingLevel="h1" size="2xl" ouiaId="manifest-details-title">
112
+ {shortDigest}
113
+ </Title>
114
+ </GridItem>
115
+
116
+ <GridItem span={12}>
117
+ <Grid hasGutter>
118
+ <GridItem span={6}>
119
+ <TextContent>
120
+ <Text component={TextVariants.h6} ouiaId="manifest-name-label">{__('Name')}</Text>
121
+ <Text ouiaId="manifest-name-value">{manifestData.name || 'N/A'}</Text>
122
+ </TextContent>
123
+ </GridItem>
124
+
125
+ <GridItem span={6}>
126
+ <TextContent>
127
+ <Text component={TextVariants.h6} ouiaId="manifest-creation-label">{__('Creation')}</Text>
128
+ {manifest?.created_at ? (
129
+ <LongDateTime date={manifest.created_at} showRelativeTimeTooltip />
130
+ ) : (
131
+ <Text ouiaId="manifest-creation-value">N/A</Text>
132
+ )}
133
+ </TextContent>
134
+ </GridItem>
135
+
136
+ <GridItem span={6}>
137
+ <TextContent>
138
+ <Text component={TextVariants.h6} ouiaId="manifest-repository-label">{__('Repositories')}</Text>
139
+ <Text ouiaId="manifest-repository-value">
140
+ {libraryRepositories.length === 0 ? (
141
+ 'N/A'
142
+ ) : (
143
+ libraryRepositories.map((repo, index) => (
144
+ <React.Fragment key={repo.id}>
145
+ {index > 0 && ', '}
146
+ <a
147
+ href={`/products/${repo.product_id}/repositories/${repo.id}`}
148
+ target="_blank"
149
+ rel="noopener noreferrer"
150
+ >
151
+ {repo.name}
152
+ </a>
153
+ </React.Fragment>
154
+ ))
155
+ )}
156
+ </Text>
157
+ </TextContent>
158
+ </GridItem>
159
+
160
+ <GridItem span={6}>
161
+ <TextContent>
162
+ <Text component={TextVariants.h6} ouiaId="manifest-modified-label">{__('Modified')}</Text>
163
+ {manifest?.updated_at ? (
164
+ <LongDateTime date={manifest.updated_at} showRelativeTimeTooltip />
165
+ ) : (
166
+ <Text ouiaId="manifest-modified-value">N/A</Text>
167
+ )}
168
+ </TextContent>
169
+ </GridItem>
170
+
171
+ <GridItem span={6}>
172
+ <TextContent>
173
+ <Text component={TextVariants.h6} ouiaId="manifest-digest-label">{__('Digest')}</Text>
174
+ {digest !== 'N/A' ? (
175
+ <ClipboardCopy variant="inline-compact" clickTip="Copied">
176
+ {digest}
177
+ </ClipboardCopy>
178
+ ) : (
179
+ <Text ouiaId="manifest-digest-value">N/A</Text>
180
+ )}
181
+ </TextContent>
182
+ </GridItem>
183
+
184
+ <GridItem span={6}>
185
+ <TextContent>
186
+ <Text component={TextVariants.h6} ouiaId="manifest-type-label">{__('Type')}</Text>
187
+ <Text ouiaId="manifest-type-value">{manifestType}</Text>
188
+ </TextContent>
189
+ </GridItem>
190
+
191
+ <GridItem span={6} />
192
+
193
+ <GridItem span={6}>
194
+ <TextContent>
195
+ <Text component={TextVariants.h6} ouiaId="manifest-labels-label">{__('Labels')}</Text>
196
+ {labelKeys.length === 0 ? (
197
+ <div>{__('No labels')}</div>
198
+ ) : (
199
+ <Flex spaceItems={{ default: 'spaceItemsSm' }} flexWrap={{ default: 'wrap' }}>
200
+ {labelKeys.map(key => (
201
+ <FlexItem key={key}>
202
+ <Label color="grey">
203
+ {key} = {labels[key]}
204
+ </Label>
205
+ </FlexItem>
206
+ ))}
207
+ </Flex>
208
+ )}
209
+ </TextContent>
210
+ </GridItem>
211
+ </Grid>
212
+ </GridItem>
213
+ </Grid>
214
+ </PageSection>
215
+ );
216
+ };
217
+
218
+ export default ManifestDetails;
@@ -0,0 +1,15 @@
1
+ import { API_OPERATIONS, get } from 'foremanReact/redux/API';
2
+ import api, { orgId } from '../../../../services/api';
3
+
4
+ export const DOCKER_TAG_DETAILS_KEY = 'DOCKER_TAG_DETAILS';
5
+
6
+ export const dockerTagDetailsKey = id => `${DOCKER_TAG_DETAILS_KEY}_${id}`;
7
+
8
+ const getDockerTagDetails = (id, extraParams = {}) => get({
9
+ type: API_OPERATIONS.GET,
10
+ key: dockerTagDetailsKey(id),
11
+ params: { organization_id: orgId(), ...extraParams },
12
+ url: api.getApiUrl(`/docker_tags/${id}`),
13
+ });
14
+
15
+ export default getDockerTagDetails;
@@ -0,0 +1,16 @@
1
+ import { STATUS } from 'foremanReact/constants';
2
+ import {
3
+ selectAPIResponse,
4
+ selectAPIStatus,
5
+ selectAPIError,
6
+ } from 'foremanReact/redux/API/APISelectors';
7
+ import { dockerTagDetailsKey } from './ManifestDetailsActions';
8
+
9
+ export const selectDockerTagDetails = (state, id) =>
10
+ selectAPIResponse(state, dockerTagDetailsKey(id)) || {};
11
+
12
+ export const selectDockerTagDetailStatus =
13
+ (state, id) => selectAPIStatus(state, dockerTagDetailsKey(id)) || STATUS.PENDING;
14
+
15
+ export const selectDockerTagDetailError =
16
+ (state, id) => selectAPIError(state, dockerTagDetailsKey(id));
@@ -0,0 +1,395 @@
1
+ import React from 'react';
2
+ import { Route } from 'react-router-dom';
3
+ import { renderWithRedux, patientlyWaitFor } from 'react-testing-lib-wrapper';
4
+ import { nockInstance, assertNockRequest } from '../../../../../test-utils/nockWrapper';
5
+ import api from '../../../../../services/api';
6
+ import ManifestDetails from '../ManifestDetails';
7
+ import { DOCKER_TAG_DETAILS_KEY } from '../ManifestDetailsActions';
8
+ import manifestDetailsData from './manifestDetails.fixtures.json';
9
+ import manifestListData from './manifestList.fixtures.json';
10
+
11
+ const withManifestRoute = component => <Route path="/labs/container_images/:id([0-9]+)">{component}</Route>;
12
+
13
+ const renderOptions = (tagId = 2) => ({
14
+ apiNamespace: `${DOCKER_TAG_DETAILS_KEY}_${tagId}`,
15
+ routerParams: {
16
+ initialEntries: [{ pathname: `/labs/container_images/${tagId}` }],
17
+ initialIndex: 1,
18
+ },
19
+ });
20
+
21
+ const manifestDetailsPath = id => api.getApiUrl(`/docker_tags/${id}`);
22
+
23
+ describe('ManifestDetails', () => {
24
+ test('Can call API and display manifest details on load', async () => {
25
+ const scope = nockInstance
26
+ .get(manifestDetailsPath(2))
27
+ .query(true)
28
+ .reply(200, manifestDetailsData);
29
+
30
+ const { getByText, getAllByText } = renderWithRedux(
31
+ withManifestRoute(<ManifestDetails />),
32
+ renderOptions(2),
33
+ );
34
+
35
+ await patientlyWaitFor(() => {
36
+ expect(getByText('v1.0')).toBeInTheDocument();
37
+ });
38
+
39
+ // Check field labels
40
+ expect(getByText('Name')).toBeInTheDocument();
41
+ expect(getByText('Type')).toBeInTheDocument();
42
+ expect(getByText('Repositories')).toBeInTheDocument();
43
+ expect(getByText('Digest')).toBeInTheDocument();
44
+ expect(getByText('Creation')).toBeInTheDocument();
45
+ expect(getByText('Modified')).toBeInTheDocument();
46
+ expect(getByText('Labels')).toBeInTheDocument();
47
+
48
+ // Check values
49
+ expect(getAllByText('v1.0')[0]).toBeInTheDocument();
50
+ expect(getByText('ubi9-container')).toBeInTheDocument();
51
+
52
+ // Check labels are displayed
53
+ expect(getByText(/architecture/)).toBeInTheDocument();
54
+ expect(getByText(/x86_64/)).toBeInTheDocument();
55
+
56
+ assertNockRequest(scope);
57
+ });
58
+
59
+ test('Displays loading state initially', () => {
60
+ nockInstance
61
+ .get(manifestDetailsPath(2))
62
+ .query(true)
63
+ .delay(1000)
64
+ .reply(200, manifestDetailsData);
65
+
66
+ const { getByText } = renderWithRedux(
67
+ withManifestRoute(<ManifestDetails />),
68
+ renderOptions(2),
69
+ );
70
+
71
+ expect(getByText('Loading')).toBeInTheDocument();
72
+ });
73
+
74
+ test('Displays only library repositories', async () => {
75
+ const scope = nockInstance
76
+ .get(manifestDetailsPath(2))
77
+ .query(true)
78
+ .reply(200, manifestDetailsData);
79
+
80
+ const { getByText, queryByText } = renderWithRedux(
81
+ withManifestRoute(<ManifestDetails />),
82
+ renderOptions(2),
83
+ );
84
+
85
+ await patientlyWaitFor(() => {
86
+ expect(getByText('ubi9-container')).toBeInTheDocument();
87
+ });
88
+
89
+ // Should display Repositories label
90
+ expect(getByText('Repositories')).toBeInTheDocument();
91
+
92
+ // Should show library repository
93
+ expect(getByText('ubi9-container')).toBeInTheDocument();
94
+
95
+ // Should NOT show non-library repository
96
+ expect(queryByText('ubi9-container-dev')).not.toBeInTheDocument();
97
+
98
+ assertNockRequest(scope);
99
+ });
100
+
101
+ test('Repository links are clickable and have correct URLs', async () => {
102
+ const scope = nockInstance
103
+ .get(manifestDetailsPath(2))
104
+ .query(true)
105
+ .reply(200, manifestDetailsData);
106
+
107
+ const { getByText } = renderWithRedux(
108
+ withManifestRoute(<ManifestDetails />),
109
+ renderOptions(2),
110
+ );
111
+
112
+ await patientlyWaitFor(() => {
113
+ expect(getByText('ubi9-container')).toBeInTheDocument();
114
+ });
115
+
116
+ const repoLink = getByText('ubi9-container').closest('a');
117
+ expect(repoLink).toBeInTheDocument();
118
+ expect(repoLink).toHaveAttribute('href', '/products/5/repositories/10');
119
+ expect(repoLink).toHaveAttribute('target', '_blank');
120
+ expect(repoLink).toHaveAttribute('rel', 'noopener noreferrer');
121
+
122
+ assertNockRequest(scope);
123
+ });
124
+
125
+ test('Displays "No labels" when labels are empty', async () => {
126
+ const dataWithoutLabels = {
127
+ ...manifestDetailsData,
128
+ manifest: {
129
+ ...manifestDetailsData.manifest,
130
+ labels: {},
131
+ },
132
+ };
133
+
134
+ const scope = nockInstance
135
+ .get(manifestDetailsPath(2))
136
+ .query(true)
137
+ .reply(200, dataWithoutLabels);
138
+
139
+ const { getByText } = renderWithRedux(
140
+ withManifestRoute(<ManifestDetails />),
141
+ renderOptions(2),
142
+ );
143
+
144
+ await patientlyWaitFor(() => {
145
+ expect(getByText('No labels')).toBeInTheDocument();
146
+ });
147
+
148
+ assertNockRequest(scope);
149
+ });
150
+
151
+ test('Handles manifest list with child manifest query param', async () => {
152
+ const scope = nockInstance
153
+ .get(manifestDetailsPath(1))
154
+ .query(true)
155
+ .reply(200, manifestListData);
156
+
157
+ const customRenderOptions = {
158
+ apiNamespace: `${DOCKER_TAG_DETAILS_KEY}_1`,
159
+ routerParams: {
160
+ initialEntries: [{ pathname: '/labs/container_images/1', search: '?manifest=102' }],
161
+ initialIndex: 1,
162
+ },
163
+ };
164
+
165
+ const { getAllByText } = renderWithRedux(
166
+ withManifestRoute(<ManifestDetails />),
167
+ customRenderOptions,
168
+ );
169
+
170
+ await patientlyWaitFor(() => {
171
+ // Should display child manifest digest in short form
172
+ const elements = getAllByText(/sha256:1111aaaa2222/);
173
+ expect(elements.length).toBeGreaterThan(0);
174
+ });
175
+
176
+ assertNockRequest(scope);
177
+ });
178
+
179
+ test('Breadcrumb navigates back to container images list', async () => {
180
+ const scope = nockInstance
181
+ .get(manifestDetailsPath(2))
182
+ .query(true)
183
+ .reply(200, manifestDetailsData);
184
+
185
+ const { getByText } = renderWithRedux(
186
+ withManifestRoute(<ManifestDetails />),
187
+ renderOptions(2),
188
+ );
189
+
190
+ await patientlyWaitFor(() => {
191
+ expect(getByText('Container images')).toBeInTheDocument();
192
+ });
193
+
194
+ const breadcrumbLink = getByText('Container images');
195
+ expect(breadcrumbLink).toBeInTheDocument();
196
+
197
+ assertNockRequest(scope);
198
+ });
199
+
200
+ test('Displays error message on 404 API error', async () => {
201
+ const scope = nockInstance
202
+ .get(manifestDetailsPath(999))
203
+ .query(true)
204
+ .reply(404, {
205
+ error: { message: 'Not Found' },
206
+ });
207
+
208
+ const { getByText } = renderWithRedux(
209
+ withManifestRoute(<ManifestDetails />),
210
+ renderOptions(999),
211
+ );
212
+
213
+ await patientlyWaitFor(() => {
214
+ expect(getByText('Not Found')).toBeInTheDocument();
215
+ });
216
+
217
+ assertNockRequest(scope);
218
+ });
219
+
220
+ test('Displays error message on 500 API error', async () => {
221
+ const scope = nockInstance
222
+ .get(manifestDetailsPath(2))
223
+ .query(true)
224
+ .reply(500, {
225
+ error: { message: 'Internal Server Error' },
226
+ });
227
+
228
+ const { getByText } = renderWithRedux(
229
+ withManifestRoute(<ManifestDetails />),
230
+ renderOptions(2),
231
+ );
232
+
233
+ await patientlyWaitFor(() => {
234
+ expect(getByText(/error/i)).toBeInTheDocument();
235
+ });
236
+
237
+ assertNockRequest(scope);
238
+ });
239
+
240
+ test('Handles manifest list with no child manifests', async () => {
241
+ const dataWithEmptyManifests = {
242
+ ...manifestDetailsData,
243
+ manifest: {
244
+ ...manifestDetailsData.manifest,
245
+ manifest_type: 'list',
246
+ manifests: [],
247
+ },
248
+ };
249
+
250
+ const scope = nockInstance
251
+ .get(manifestDetailsPath(2))
252
+ .query(true)
253
+ .reply(200, dataWithEmptyManifests);
254
+
255
+ const { getByText } = renderWithRedux(
256
+ withManifestRoute(<ManifestDetails />),
257
+ renderOptions(2),
258
+ );
259
+
260
+ await patientlyWaitFor(() => {
261
+ expect(getByText('v1.0')).toBeInTheDocument();
262
+ });
263
+
264
+ // Should still display basic manifest information
265
+ expect(getByText('Name')).toBeInTheDocument();
266
+ expect(getByText('Repositories')).toBeInTheDocument();
267
+ expect(getByText('Digest')).toBeInTheDocument();
268
+
269
+ assertNockRequest(scope);
270
+ });
271
+
272
+ test('Displays N/A when no library repositories are present', async () => {
273
+ const dataWithoutLibraryRepos = {
274
+ ...manifestDetailsData,
275
+ repositories: [
276
+ {
277
+ id: 1,
278
+ name: 'non-library-repo',
279
+ library_instance: false,
280
+ },
281
+ {
282
+ id: 2,
283
+ name: 'another-non-library-repo',
284
+ library_instance: false,
285
+ },
286
+ ],
287
+ };
288
+
289
+ const scope = nockInstance
290
+ .get(manifestDetailsPath(2))
291
+ .query(true)
292
+ .reply(200, dataWithoutLibraryRepos);
293
+
294
+ const { getByText, queryByText } = renderWithRedux(
295
+ withManifestRoute(<ManifestDetails />),
296
+ renderOptions(2),
297
+ );
298
+
299
+ await patientlyWaitFor(() => {
300
+ expect(getByText('v1.0')).toBeInTheDocument();
301
+ });
302
+
303
+ // Repository field should show N/A when no library repositories
304
+ expect(getByText('Repositories')).toBeInTheDocument();
305
+ const repositoryValues = queryByText('N/A');
306
+ expect(repositoryValues).toBeInTheDocument();
307
+
308
+ // Non-library repos should not be displayed
309
+ expect(queryByText('non-library-repo')).not.toBeInTheDocument();
310
+ expect(queryByText('another-non-library-repo')).not.toBeInTheDocument();
311
+
312
+ assertNockRequest(scope);
313
+ });
314
+
315
+ test('Displays correct manifest types', async () => {
316
+ // Test bootable image
317
+ const bootableData = {
318
+ ...manifestDetailsData,
319
+ manifest: {
320
+ ...manifestDetailsData.manifest,
321
+ manifest_type: 'image',
322
+ is_bootable: true,
323
+ is_flatpak: false,
324
+ },
325
+ };
326
+
327
+ const bootableScope = nockInstance
328
+ .get(manifestDetailsPath(3))
329
+ .query(true)
330
+ .reply(200, bootableData);
331
+
332
+ const { getByText: getByTextBootable } = renderWithRedux(
333
+ withManifestRoute(<ManifestDetails />),
334
+ renderOptions(3),
335
+ );
336
+
337
+ await patientlyWaitFor(() => {
338
+ expect(getByTextBootable('Bootable')).toBeInTheDocument();
339
+ });
340
+
341
+ assertNockRequest(bootableScope);
342
+
343
+ // Test flatpak image
344
+ const flatpakData = {
345
+ ...manifestDetailsData,
346
+ manifest: {
347
+ ...manifestDetailsData.manifest,
348
+ manifest_type: 'image',
349
+ is_bootable: false,
350
+ is_flatpak: true,
351
+ },
352
+ };
353
+
354
+ const flatpakScope = nockInstance
355
+ .get(manifestDetailsPath(4))
356
+ .query(true)
357
+ .reply(200, flatpakData);
358
+
359
+ const { getByText: getByTextFlatpak } = renderWithRedux(
360
+ withManifestRoute(<ManifestDetails />),
361
+ renderOptions(4),
362
+ );
363
+
364
+ await patientlyWaitFor(() => {
365
+ expect(getByTextFlatpak('Flatpak')).toBeInTheDocument();
366
+ });
367
+
368
+ assertNockRequest(flatpakScope);
369
+
370
+ // Test manifest list
371
+ const listData = {
372
+ ...manifestDetailsData,
373
+ manifest: {
374
+ ...manifestDetailsData.manifest,
375
+ manifest_type: 'list',
376
+ },
377
+ };
378
+
379
+ const listScope = nockInstance
380
+ .get(manifestDetailsPath(5))
381
+ .query(true)
382
+ .reply(200, listData);
383
+
384
+ const { getByText: getByTextList } = renderWithRedux(
385
+ withManifestRoute(<ManifestDetails />),
386
+ renderOptions(5),
387
+ );
388
+
389
+ await patientlyWaitFor(() => {
390
+ expect(getByTextList('List')).toBeInTheDocument();
391
+ });
392
+
393
+ assertNockRequest(listScope);
394
+ });
395
+ });
@@ -0,0 +1,43 @@
1
+ {
2
+ "id": 2,
3
+ "name": "v1.0",
4
+ "repositories": [
5
+ {
6
+ "id": 10,
7
+ "name": "ubi9-container",
8
+ "full_path": "Default_Organization/Library/ubi9-container",
9
+ "library_instance": true,
10
+ "product_id": 5,
11
+ "product_name": "Red Hat Universal Base Image"
12
+ },
13
+ {
14
+ "id": 11,
15
+ "name": "ubi9-container-dev",
16
+ "full_path": "Default_Organization/Dev/ubi9-container",
17
+ "library_instance": false,
18
+ "product_id": 5,
19
+ "product_name": "Red Hat Universal Base Image"
20
+ }
21
+ ],
22
+ "product": {
23
+ "id": 5,
24
+ "name": "Red Hat Universal Base Image"
25
+ },
26
+ "manifest": {
27
+ "id": 104,
28
+ "digest": "sha256:efgh5678901234efgh5678901234efgh5678901234efgh5678901234efgh5678",
29
+ "schema_version": 2,
30
+ "manifest_type": "image",
31
+ "labels": {
32
+ "architecture": "x86_64",
33
+ "build-date": "2024-08-21T11:28:48",
34
+ "io.buildah.version": "1.37.1",
35
+ "version": "v1.0"
36
+ },
37
+ "annotations": {},
38
+ "is_bootable": true,
39
+ "is_flatpak": false,
40
+ "created_at": "2024-08-21T11:28:48.000Z",
41
+ "updated_at": "2024-08-21T11:28:48.000Z"
42
+ }
43
+ }