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,335 @@
1
+ import React from 'react';
2
+ import { renderWithRedux, patientlyWaitFor, act } from 'react-testing-lib-wrapper';
3
+ import { nockInstance, assertNockRequest, mockAutocomplete } from '../../../../test-utils/nockWrapper';
4
+ import SyncedContainerImagesPage from '../SyncedContainerImagesPage';
5
+ import syncedImagesData from './syncedContainerImages.fixtures.json';
6
+
7
+ const syncedImagesUrl = '/katello/api/v2/docker_tags';
8
+ const autocompleteUrl = '/docker_tags/auto_complete_search';
9
+ const autocompleteQuery = {
10
+ organization_id: '1',
11
+ search: '',
12
+ };
13
+
14
+ const buildDockerTag = id => ({
15
+ id,
16
+ name: `tag-${id}`,
17
+ manifest: {
18
+ id: 100 + id,
19
+ digest: `sha256:digest${id}digest${id}digest${id}digest${id}digest${id}digest${id}digest${id}`,
20
+ manifest_type: 'image',
21
+ is_bootable: false,
22
+ is_flatpak: false,
23
+ },
24
+ });
25
+
26
+ const createSyncedImages = (amount) => {
27
+ const response = {
28
+ total: amount,
29
+ subtotal: amount,
30
+ page: 1,
31
+ per_page: 20,
32
+ error: null,
33
+ search: null,
34
+ sort: {
35
+ by: 'name',
36
+ order: 'asc',
37
+ },
38
+ results: [],
39
+ };
40
+
41
+ [...Array(amount).keys()].forEach((_, i) => response.results.push(buildDockerTag(i + 1)));
42
+
43
+ return response;
44
+ };
45
+
46
+ let latestTag;
47
+ let v10Tag;
48
+ let flatpakTag;
49
+ let childManifest1;
50
+ let childManifest2;
51
+
52
+ beforeEach(() => {
53
+ const { results } = syncedImagesData;
54
+ [latestTag, v10Tag, flatpakTag] = results;
55
+ if (latestTag.manifest?.manifests) {
56
+ [childManifest1, childManifest2] = latestTag.manifest.manifests;
57
+ }
58
+ });
59
+
60
+ test('SyncedContainerImagesPage renders correctly', async (done) => {
61
+ const autocompleteScope = mockAutocomplete(nockInstance, autocompleteUrl, autocompleteQuery);
62
+ const scope = nockInstance
63
+ .get(syncedImagesUrl)
64
+ .query(true)
65
+ .reply(200, syncedImagesData);
66
+
67
+ const { queryByText } = renderWithRedux(<SyncedContainerImagesPage />);
68
+
69
+ expect(queryByText(latestTag.name)).toBeNull();
70
+
71
+ await patientlyWaitFor(() => {
72
+ expect(queryByText(latestTag.name)).toBeVisible();
73
+ expect(queryByText(v10Tag.name)).toBeVisible();
74
+ expect(queryByText(flatpakTag.name)).toBeVisible();
75
+ });
76
+
77
+ assertNockRequest(autocompleteScope);
78
+ assertNockRequest(scope, done);
79
+ act(done);
80
+ });
81
+
82
+ test('Can expand manifest list and show child manifests', async (done) => {
83
+ const autocompleteScope = mockAutocomplete(nockInstance, autocompleteUrl, autocompleteQuery);
84
+ const scope = nockInstance
85
+ .get(syncedImagesUrl)
86
+ .query(true)
87
+ .reply(200, syncedImagesData);
88
+
89
+ const {
90
+ queryByText, queryAllByRole,
91
+ } = renderWithRedux(<SyncedContainerImagesPage />);
92
+
93
+ expect(queryByText(latestTag.name)).toBeNull();
94
+
95
+ await patientlyWaitFor(() => {
96
+ expect(queryByText(latestTag.name)).toBeVisible();
97
+
98
+ // Find and click the expand button for the manifest list
99
+ const expandButtons = queryAllByRole('button');
100
+ const expandButton = expandButtons.find(btn =>
101
+ btn.getAttribute('aria-labelledby')?.includes(`synced-containers-expander-${latestTag.id}`));
102
+
103
+ if (expandButton) {
104
+ expandButton.click();
105
+ }
106
+ });
107
+
108
+ await patientlyWaitFor(() => {
109
+ // Check that child manifest digests appear
110
+ expect(queryByText(childManifest1.digest)).toBeVisible();
111
+ expect(queryByText(childManifest2.digest)).toBeVisible();
112
+ });
113
+
114
+ assertNockRequest(autocompleteScope);
115
+ assertNockRequest(scope, done);
116
+ act(done);
117
+ });
118
+
119
+ test('Displays correct manifest types', async (done) => {
120
+ const autocompleteScope = mockAutocomplete(nockInstance, autocompleteUrl, autocompleteQuery);
121
+ const scope = nockInstance
122
+ .get(syncedImagesUrl)
123
+ .query(true)
124
+ .reply(200, syncedImagesData);
125
+
126
+ const { queryByText, queryAllByText } = renderWithRedux(<SyncedContainerImagesPage />);
127
+
128
+ await patientlyWaitFor(() => {
129
+ // Check that manifest types are displayed correctly
130
+ expect(queryByText('List')).toBeVisible(); // Capitalized 'list'
131
+ expect(queryAllByText('Bootable').length).toBeGreaterThan(0); // For bootable images
132
+ expect(queryByText('Flatpak')).toBeVisible(); // For flatpak images
133
+ });
134
+
135
+ assertNockRequest(autocompleteScope);
136
+ assertNockRequest(scope, done);
137
+ act(done);
138
+ });
139
+
140
+ test('Displays manifest digests correctly', async (done) => {
141
+ const autocompleteScope = mockAutocomplete(nockInstance, autocompleteUrl, autocompleteQuery);
142
+ const scope = nockInstance
143
+ .get(syncedImagesUrl)
144
+ .query(true)
145
+ .reply(200, syncedImagesData);
146
+
147
+ const { queryByText } = renderWithRedux(<SyncedContainerImagesPage />);
148
+
149
+ await patientlyWaitFor(() => {
150
+ expect(queryByText(latestTag.manifest.digest)).toBeVisible();
151
+ expect(queryByText(v10Tag.manifest.digest)).toBeVisible();
152
+ });
153
+
154
+ assertNockRequest(autocompleteScope);
155
+ assertNockRequest(scope, done);
156
+ act(done);
157
+ });
158
+
159
+ test('Child manifests remain hidden when not expanded', async (done) => {
160
+ const autocompleteScope = mockAutocomplete(nockInstance, autocompleteUrl, autocompleteQuery);
161
+ const scope = nockInstance
162
+ .get(syncedImagesUrl)
163
+ .query(true)
164
+ .reply(200, syncedImagesData);
165
+
166
+ const { queryByText } = renderWithRedux(<SyncedContainerImagesPage />);
167
+
168
+ await patientlyWaitFor(() => {
169
+ expect(queryByText(latestTag.name)).toBeVisible();
170
+ // Child manifests should not be visible initially
171
+ expect(queryByText(childManifest1.digest)?.closest('td')).not.toBeVisible();
172
+ expect(queryByText(childManifest2.digest)?.closest('td')).not.toBeVisible();
173
+ });
174
+
175
+ assertNockRequest(autocompleteScope);
176
+ assertNockRequest(scope, done);
177
+ act(done);
178
+ });
179
+
180
+ test('Can handle no container images being present', async (done) => {
181
+ const autocompleteScope = mockAutocomplete(nockInstance, autocompleteUrl, autocompleteQuery);
182
+ const noResults = {
183
+ total: 0,
184
+ subtotal: 0,
185
+ page: 1,
186
+ per_page: 20,
187
+ results: [],
188
+ };
189
+ const scope = nockInstance
190
+ .get(syncedImagesUrl)
191
+ .query(true)
192
+ .reply(200, noResults);
193
+
194
+ const { queryByText } = renderWithRedux(<SyncedContainerImagesPage />);
195
+
196
+ expect(queryByText(latestTag.name)).toBeNull();
197
+ await patientlyWaitFor(() => expect(queryByText('No Results')).toBeInTheDocument());
198
+
199
+ assertNockRequest(autocompleteScope);
200
+ assertNockRequest(scope, done);
201
+ });
202
+
203
+ test('Displays loading state while fetching data', async (done) => {
204
+ const autocompleteScope = mockAutocomplete(nockInstance, autocompleteUrl, autocompleteQuery);
205
+ const scope = nockInstance
206
+ .get(syncedImagesUrl)
207
+ .query(true)
208
+ .reply(200, syncedImagesData);
209
+
210
+ const { queryByText } = renderWithRedux(<SyncedContainerImagesPage />);
211
+
212
+ // Check for loading state
213
+ expect(queryByText('Loading...')).toBeInTheDocument();
214
+
215
+ await patientlyWaitFor(() => {
216
+ expect(queryByText(latestTag.name)).toBeVisible();
217
+ expect(queryByText('Loading...')).not.toBeInTheDocument();
218
+ });
219
+
220
+ assertNockRequest(autocompleteScope);
221
+ assertNockRequest(scope, done);
222
+ act(done);
223
+ });
224
+
225
+ test('Can handle pagination', async (done) => {
226
+ const largeSyncedData = createSyncedImages(100);
227
+ const { results } = largeSyncedData;
228
+ const firstPage = { ...largeSyncedData, results: results.slice(0, 20) };
229
+ const secondPage = { ...largeSyncedData, page: 2, results: results.slice(20, 40) };
230
+ const autocompleteScope = mockAutocomplete(nockInstance, autocompleteUrl, autocompleteQuery);
231
+
232
+ // Match first page API request
233
+ const firstPageScope = nockInstance
234
+ .get(syncedImagesUrl)
235
+ .query(true)
236
+ .reply(200, firstPage);
237
+
238
+ // Match second page API request
239
+ const secondPageScope = nockInstance
240
+ .get(syncedImagesUrl)
241
+ .query(actualQueryObject => (parseInt(actualQueryObject.page, 10) === 2))
242
+ .reply(200, secondPage);
243
+
244
+ const { queryByText, getAllByLabelText } = renderWithRedux(<SyncedContainerImagesPage />);
245
+
246
+ // Wait for first paginated page to load
247
+ await patientlyWaitFor(() => {
248
+ expect(queryByText(results[0].name)).toBeInTheDocument();
249
+ expect(queryByText(results[19].name)).toBeInTheDocument();
250
+ expect(queryByText(results[21].name)).not.toBeInTheDocument();
251
+ });
252
+
253
+ // Navigate to second page
254
+ const [top, bottom] = getAllByLabelText('Go to next page');
255
+ expect(top).toBeInTheDocument();
256
+ expect(bottom).toBeInTheDocument();
257
+ bottom.click();
258
+
259
+ // Wait for second paginated page to load
260
+ await patientlyWaitFor(() => {
261
+ expect(queryByText(results[20].name)).toBeInTheDocument();
262
+ expect(queryByText(results[39].name)).toBeInTheDocument();
263
+ expect(queryByText(results[41].name)).not.toBeInTheDocument();
264
+ });
265
+
266
+ assertNockRequest(autocompleteScope);
267
+ assertNockRequest(firstPageScope);
268
+ assertNockRequest(secondPageScope, done);
269
+ act(done);
270
+ });
271
+
272
+ test('Handles tags with manifest_schema1', async (done) => {
273
+ const dataWithSchema1 = {
274
+ ...syncedImagesData,
275
+ results: [
276
+ {
277
+ id: 10,
278
+ name: 'schema1-tag',
279
+ manifest_schema1: {
280
+ id: 110,
281
+ digest: 'sha256:schema1digestschema1digestschema1digestschema1digestschema1digest',
282
+ manifest_type: 'image',
283
+ is_bootable: false,
284
+ is_flatpak: false,
285
+ },
286
+ },
287
+ ],
288
+ };
289
+
290
+ const autocompleteScope = mockAutocomplete(nockInstance, autocompleteUrl, autocompleteQuery);
291
+ const scope = nockInstance
292
+ .get(syncedImagesUrl)
293
+ .query(true)
294
+ .reply(200, dataWithSchema1);
295
+
296
+ const { queryByText } = renderWithRedux(<SyncedContainerImagesPage />);
297
+
298
+ await patientlyWaitFor(() => {
299
+ expect(queryByText('schema1-tag')).toBeVisible();
300
+ expect(queryByText('sha256:schema1digestschema1digestschema1digestschema1digestschema1digest')).toBeVisible();
301
+ });
302
+
303
+ assertNockRequest(autocompleteScope);
304
+ assertNockRequest(scope, done);
305
+ act(done);
306
+ });
307
+
308
+ test('Shows N/A for missing manifest data', async (done) => {
309
+ const dataWithMissingManifest = {
310
+ ...syncedImagesData,
311
+ results: [
312
+ {
313
+ id: 11,
314
+ name: 'no-manifest-tag',
315
+ },
316
+ ],
317
+ };
318
+
319
+ const autocompleteScope = mockAutocomplete(nockInstance, autocompleteUrl, autocompleteQuery);
320
+ const scope = nockInstance
321
+ .get(syncedImagesUrl)
322
+ .query(true)
323
+ .reply(200, dataWithMissingManifest);
324
+
325
+ const { queryByText, queryAllByText } = renderWithRedux(<SyncedContainerImagesPage />);
326
+
327
+ await patientlyWaitFor(() => {
328
+ expect(queryByText('no-manifest-tag')).toBeVisible();
329
+ expect(queryAllByText('N/A').length).toBeGreaterThan(0);
330
+ });
331
+
332
+ assertNockRequest(autocompleteScope);
333
+ assertNockRequest(scope, done);
334
+ act(done);
335
+ });
@@ -0,0 +1,105 @@
1
+ {
2
+ "total": 3,
3
+ "subtotal": 3,
4
+ "page": 1,
5
+ "per_page": 20,
6
+ "error": null,
7
+ "search": null,
8
+ "sort": {
9
+ "by": "name",
10
+ "order": "asc"
11
+ },
12
+ "results": [
13
+ {
14
+ "id": 1,
15
+ "name": "latest",
16
+ "product": {
17
+ "id": 1,
18
+ "name": "Red Hat Enterprise Linux"
19
+ },
20
+ "repositories": [
21
+ {
22
+ "id": 10,
23
+ "name": "RHEL Base Images",
24
+ "full_path": "Library/RHEL Base Images",
25
+ "library_instance": true,
26
+ "product_id": 1,
27
+ "product_name": "Red Hat Enterprise Linux"
28
+ }
29
+ ],
30
+ "manifest": {
31
+ "id": 101,
32
+ "digest": "sha256:abcd1234567890abcd1234567890abcd1234567890abcd1234567890abcd1234",
33
+ "manifest_type": "list",
34
+ "is_bootable": false,
35
+ "is_flatpak": false,
36
+ "manifests": [
37
+ {
38
+ "id": 102,
39
+ "digest": "sha256:1111aaaa2222bbbb3333cccc4444dddd5555eeee6666ffff7777gggg8888hhhh",
40
+ "manifest_type": "image",
41
+ "is_bootable": false,
42
+ "is_flatpak": false
43
+ },
44
+ {
45
+ "id": 103,
46
+ "digest": "sha256:2222bbbb3333cccc4444dddd5555eeee6666ffff7777gggg8888hhhh9999iiii",
47
+ "manifest_type": "image",
48
+ "is_bootable": true,
49
+ "is_flatpak": false
50
+ }
51
+ ]
52
+ }
53
+ },
54
+ {
55
+ "id": 2,
56
+ "name": "v1.0",
57
+ "product": {
58
+ "id": 2,
59
+ "name": "Container Tools"
60
+ },
61
+ "repositories": [
62
+ {
63
+ "id": 20,
64
+ "name": "Container Images",
65
+ "full_path": "Library/Container Images",
66
+ "library_instance": true,
67
+ "product_id": 2,
68
+ "product_name": "Container Tools"
69
+ }
70
+ ],
71
+ "manifest": {
72
+ "id": 104,
73
+ "digest": "sha256:efgh5678901234efgh5678901234efgh5678901234efgh5678901234efgh5678",
74
+ "manifest_type": "image",
75
+ "is_bootable": true,
76
+ "is_flatpak": false
77
+ }
78
+ },
79
+ {
80
+ "id": 3,
81
+ "name": "flatpak-app",
82
+ "product": {
83
+ "id": 3,
84
+ "name": "Flatpak Applications"
85
+ },
86
+ "repositories": [
87
+ {
88
+ "id": 30,
89
+ "name": "Flatpak Repository",
90
+ "full_path": "Library/Flatpak Repository",
91
+ "library_instance": true,
92
+ "product_id": 3,
93
+ "product_name": "Flatpak Applications"
94
+ }
95
+ ],
96
+ "manifest_schema2": {
97
+ "id": 105,
98
+ "digest": "sha256:ijkl9012345678ijkl9012345678ijkl9012345678ijkl9012345678ijkl9012",
99
+ "manifest_type": "image",
100
+ "is_bootable": false,
101
+ "is_flatpak": true
102
+ }
103
+ }
104
+ ]
105
+ }
@@ -0,0 +1,67 @@
1
+ import React from 'react';
2
+ import PropTypes from 'prop-types';
3
+ import { Tbody, Tr, Td } from '@patternfly/react-table';
4
+ import { translate as __ } from 'foremanReact/common/I18n';
5
+ import EmptyPage from 'foremanReact/routes/common/EmptyPage';
6
+ import { STATUS } from './containerImagesHelpers';
7
+
8
+ const TableEmptyState = ({
9
+ status, results, errorMessage, colSpan,
10
+ }) => {
11
+ if (results.length > 0 && !errorMessage) {
12
+ return null;
13
+ }
14
+
15
+ return (
16
+ <Tbody>
17
+ {status === STATUS.PENDING && results.length === 0 && (
18
+ <Tr ouiaId="table-loading">
19
+ <Td colSpan={colSpan}>
20
+ <EmptyPage
21
+ message={{
22
+ type: 'loading',
23
+ text: __('Loading...'),
24
+ }}
25
+ />
26
+ </Td>
27
+ </Tr>
28
+ )}
29
+ {status !== STATUS.PENDING &&
30
+ results.length === 0 &&
31
+ !errorMessage && (
32
+ <Tr ouiaId="table-empty">
33
+ <Td colSpan={colSpan}>
34
+ <EmptyPage
35
+ message={{
36
+ type: 'empty',
37
+ }}
38
+ />
39
+ </Td>
40
+ </Tr>
41
+ )}
42
+ {errorMessage && (
43
+ <Tr ouiaId="table-error">
44
+ <Td colSpan={colSpan}>
45
+ <EmptyPage message={{ type: 'error', text: errorMessage }} />
46
+ </Td>
47
+ </Tr>
48
+ )}
49
+ </Tbody>
50
+ );
51
+ };
52
+
53
+ TableEmptyState.propTypes = {
54
+ status: PropTypes.string,
55
+ results: PropTypes.arrayOf(PropTypes.shape({})),
56
+ errorMessage: PropTypes.string,
57
+ colSpan: PropTypes.number,
58
+ };
59
+
60
+ TableEmptyState.defaultProps = {
61
+ status: STATUS.PENDING,
62
+ results: [],
63
+ errorMessage: null,
64
+ colSpan: 100,
65
+ };
66
+
67
+ export default TableEmptyState;
@@ -0,0 +1,48 @@
1
+ import { translate as __ } from 'foremanReact/common/I18n';
2
+ import { capitalize } from '../../utils/helpers';
3
+
4
+ export const STATUS = {
5
+ PENDING: 'PENDING',
6
+ RESOLVED: 'RESOLVED',
7
+ ERROR: 'ERROR',
8
+ };
9
+
10
+ export const getManifest = (data) => {
11
+ if (!data) return null;
12
+ return data.manifest || data.manifest_schema2 || data.manifest_schema1;
13
+ };
14
+
15
+ export const formatManifestType = (manifest) => {
16
+ if (!manifest || !manifest.manifest_type) return 'N/A';
17
+
18
+ if (manifest.manifest_type === 'image') {
19
+ if (manifest.is_bootable) {
20
+ return __('Bootable');
21
+ }
22
+ if (manifest.is_flatpak) {
23
+ return __('Flatpak');
24
+ }
25
+ }
26
+
27
+ return capitalize(manifest.manifest_type);
28
+ };
29
+
30
+ export const getShortDigest = (digest) => {
31
+ if (!digest) return 'N/A';
32
+ const parts = digest.split(':');
33
+ if (parts.length === 2) {
34
+ return `${parts[0]}:${parts[1].substring(0, 12)}`;
35
+ }
36
+ return digest.substring(0, 19);
37
+ };
38
+
39
+ export const hasLabelsOrAnnotations = (manifest) => {
40
+ if (!manifest) return false;
41
+ return (Object.keys(manifest.labels || {}).length > 0) ||
42
+ (Object.keys(manifest.annotations || {}).length > 0);
43
+ };
44
+
45
+ export const anyChildHasLabelsOrAnnotations = (manifest) => {
46
+ if (!manifest?.manifests) return false;
47
+ return manifest.manifests.some(child => hasLabelsOrAnnotations(child));
48
+ };
@@ -0,0 +1,4 @@
1
+ import { withRouter } from 'react-router-dom';
2
+ import ContainerImagesPage from './ContainerImagesPage';
3
+
4
+ export default withRouter(ContainerImagesPage);
@@ -27,6 +27,8 @@ import {
27
27
  } from './ContentViewCreateSelectors';
28
28
  import { LabelDependencies, LabelAutoPublish } from './ContentViewFormComponents';
29
29
  import ContentViewIcon from '../components/ContentViewIcon';
30
+ import getEnvironmentPaths from '../components/EnvironmentPaths/EnvironmentPathActions';
31
+ import EnvironmentPaths from '../components/EnvironmentPaths/EnvironmentPaths';
30
32
  import './CreateContentViewForm.scss';
31
33
 
32
34
  export const contentViewDescriptions = {
@@ -47,7 +49,7 @@ const CreateContentViewForm = ({ setModalOpen }) => {
47
49
  const [dependencies, setDependencies] = useState(false);
48
50
  const [redirect, setRedirect] = useState(false);
49
51
  const [saving, setSaving] = useState(false);
50
-
52
+ const [selectedEnvs, setSelectedEnvs] = useState([]);
51
53
  const [labelValidated, setLabelValidated] = useState('default');
52
54
  const handleLabelChange = (newLabel, _event) => {
53
55
  setLabel(newLabel);
@@ -74,9 +76,10 @@ const CreateContentViewForm = ({ setModalOpen }) => {
74
76
  }
75
77
  }, [response, status, error, saving]);
76
78
 
79
+ const checkedEnvIds = selectedEnvs?.map(env => env.id) ?? [];
77
80
  const onSave = () => {
78
81
  setSaving(true);
79
- dispatch(createContentView({
82
+ let params = {
80
83
  name,
81
84
  label,
82
85
  description,
@@ -84,9 +87,22 @@ const CreateContentViewForm = ({ setModalOpen }) => {
84
87
  rolling,
85
88
  solve_dependencies: (dependencies && !(rolling || composite)),
86
89
  auto_publish: (autoPublish && composite),
87
- }));
90
+ };
91
+ if (rolling) {
92
+ params = { ...params, environment_ids: checkedEnvIds };
93
+ }
94
+ dispatch(createContentView(params));
88
95
  };
89
96
 
97
+ useEffect(
98
+ () => {
99
+ if (rolling) {
100
+ dispatch(getEnvironmentPaths());
101
+ }
102
+ },
103
+ [rolling, dispatch],
104
+ );
105
+
90
106
  useEffect(() => {
91
107
  setLabel(name.replace(/[^A-Za-z0-9_-]/g, '_'));
92
108
  }, [name]);
@@ -230,6 +246,16 @@ const CreateContentViewForm = ({ setModalOpen }) => {
230
246
  />
231
247
  </FormGroup>
232
248
  )}
249
+ {rolling && (
250
+ <FormGroup isInline fieldId="lifecycleEnvironments" label={__('Lifecycle Environments')}>
251
+ <EnvironmentPaths
252
+ headerText=""
253
+ publishing={false}
254
+ userCheckedItems={selectedEnvs}
255
+ setUserCheckedItems={setSelectedEnvs}
256
+ />
257
+ </FormGroup>
258
+ )}
233
259
  <ActionGroup>
234
260
  <Button
235
261
  ouiaId="create-content-view-form-submit"
@@ -8,6 +8,7 @@
8
8
  "latest_version": null,
9
9
  "auto_publish": false,
10
10
  "solve_dependencies": false,
11
+ "environment_ids": [],
11
12
  "import_only": false,
12
13
  "repository_ids": [],
13
14
  "id": 34,