katello 4.17.1 → 4.18.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 (293) hide show
  1. checksums.yaml +4 -4
  2. data/app/assets/javascripts/katello/locale/bn/katello.js +148 -4
  3. data/app/assets/javascripts/katello/locale/bn_IN/katello.js +148 -4
  4. data/app/assets/javascripts/katello/locale/ca/katello.js +148 -4
  5. data/app/assets/javascripts/katello/locale/cs/katello.js +148 -4
  6. data/app/assets/javascripts/katello/locale/cs_CZ/katello.js +148 -4
  7. data/app/assets/javascripts/katello/locale/de/katello.js +147 -3
  8. data/app/assets/javascripts/katello/locale/de_AT/katello.js +148 -4
  9. data/app/assets/javascripts/katello/locale/de_DE/katello.js +148 -4
  10. data/app/assets/javascripts/katello/locale/el/katello.js +148 -4
  11. data/app/assets/javascripts/katello/locale/en/katello.js +148 -4
  12. data/app/assets/javascripts/katello/locale/en_GB/katello.js +148 -4
  13. data/app/assets/javascripts/katello/locale/en_US/katello.js +148 -4
  14. data/app/assets/javascripts/katello/locale/es/katello.js +147 -3
  15. data/app/assets/javascripts/katello/locale/et_EE/katello.js +148 -4
  16. data/app/assets/javascripts/katello/locale/fr/katello.js +147 -3
  17. data/app/assets/javascripts/katello/locale/gl/katello.js +148 -4
  18. data/app/assets/javascripts/katello/locale/gu/katello.js +148 -4
  19. data/app/assets/javascripts/katello/locale/he_IL/katello.js +148 -4
  20. data/app/assets/javascripts/katello/locale/hi/katello.js +148 -4
  21. data/app/assets/javascripts/katello/locale/id/katello.js +148 -4
  22. data/app/assets/javascripts/katello/locale/it/katello.js +148 -4
  23. data/app/assets/javascripts/katello/locale/ja/katello.js +147 -3
  24. data/app/assets/javascripts/katello/locale/ka/katello.js +147 -3
  25. data/app/assets/javascripts/katello/locale/kn/katello.js +148 -4
  26. data/app/assets/javascripts/katello/locale/ko/katello.js +147 -3
  27. data/app/assets/javascripts/katello/locale/ml_IN/katello.js +148 -4
  28. data/app/assets/javascripts/katello/locale/mr/katello.js +148 -4
  29. data/app/assets/javascripts/katello/locale/nl_NL/katello.js +148 -4
  30. data/app/assets/javascripts/katello/locale/or/katello.js +148 -4
  31. data/app/assets/javascripts/katello/locale/pa/katello.js +148 -4
  32. data/app/assets/javascripts/katello/locale/pl/katello.js +148 -4
  33. data/app/assets/javascripts/katello/locale/pl_PL/katello.js +148 -4
  34. data/app/assets/javascripts/katello/locale/pt/katello.js +148 -4
  35. data/app/assets/javascripts/katello/locale/pt_BR/katello.js +147 -3
  36. data/app/assets/javascripts/katello/locale/ro/katello.js +148 -4
  37. data/app/assets/javascripts/katello/locale/ro_RO/katello.js +148 -4
  38. data/app/assets/javascripts/katello/locale/ru/katello.js +148 -4
  39. data/app/assets/javascripts/katello/locale/sl/katello.js +148 -4
  40. data/app/assets/javascripts/katello/locale/sv_SE/katello.js +148 -4
  41. data/app/assets/javascripts/katello/locale/ta/katello.js +148 -4
  42. data/app/assets/javascripts/katello/locale/ta_IN/katello.js +148 -4
  43. data/app/assets/javascripts/katello/locale/te/katello.js +148 -4
  44. data/app/assets/javascripts/katello/locale/tr/katello.js +148 -4
  45. data/app/assets/javascripts/katello/locale/vi/katello.js +148 -4
  46. data/app/assets/javascripts/katello/locale/vi_VN/katello.js +148 -4
  47. data/app/assets/javascripts/katello/locale/zh/katello.js +148 -4
  48. data/app/assets/javascripts/katello/locale/zh_CN/katello.js +147 -3
  49. data/app/assets/javascripts/katello/locale/zh_TW/katello.js +148 -4
  50. data/app/controllers/katello/api/registry/registry_proxies_controller.rb +12 -14
  51. data/app/controllers/katello/api/v2/content_uploads_controller.rb +2 -1
  52. data/app/controllers/katello/api/v2/errata_controller.rb +16 -0
  53. data/app/controllers/katello/api/v2/flatpak_remote_repositories_controller.rb +20 -3
  54. data/app/controllers/katello/api/v2/flatpak_remotes_controller.rb +7 -3
  55. data/app/controllers/katello/api/v2/generic_content_units_controller.rb +1 -2
  56. data/app/controllers/katello/api/v2/products_controller.rb +18 -0
  57. data/app/controllers/katello/api/v2/repositories_controller.rb +5 -3
  58. data/app/controllers/katello/concerns/api/v2/hosts_bulk_actions_controller_extensions.rb +10 -0
  59. data/app/controllers/katello/concerns/api/v2/registration_commands_controller_extensions.rb +1 -0
  60. data/app/controllers/katello/concerns/filtered_auto_complete_search.rb +17 -0
  61. data/app/lib/actions/helpers/smart_proxy_sync_helper.rb +12 -0
  62. data/app/lib/actions/katello/content_view/add_rolling_repo_clone.rb +4 -4
  63. data/app/lib/actions/katello/content_view/capsule_sync.rb +8 -3
  64. data/app/lib/actions/katello/content_view/publish.rb +39 -12
  65. data/app/lib/actions/katello/flatpak/mirror_remote_repository.rb +2 -1
  66. data/app/lib/actions/katello/repository/capsule_sync.rb +11 -1
  67. data/app/lib/actions/katello/repository/import_upload.rb +2 -3
  68. data/app/lib/actions/katello/repository/sync.rb +2 -1
  69. data/app/lib/actions/katello/repository/upload_files.rb +2 -1
  70. data/app/lib/katello/concerns/bookmark_controller_validator_extensions.rb +1 -1
  71. data/app/lib/katello/resources/cdn.rb +1 -1
  72. data/app/models/katello/concerns/smart_proxy_extensions.rb +46 -8
  73. data/app/models/katello/content_view_environment.rb +1 -1
  74. data/app/models/katello/erratum.rb +26 -1
  75. data/app/models/katello/flatpak_remote.rb +0 -1
  76. data/app/models/katello/flatpak_remote_repository.rb +24 -0
  77. data/app/models/katello/glue/pulp/repos.rb +1 -1
  78. data/app/models/katello/root_repository.rb +1 -0
  79. data/app/presenters/katello/flatpak_remote_mirror_status_presenter.rb +41 -0
  80. data/app/services/katello/repository_type_manager.rb +2 -0
  81. data/app/views/foreman/job_templates/flatpak_install.erb +17 -2
  82. data/app/views/foreman/job_templates/flatpak_login_action.erb +17 -3
  83. data/app/views/foreman/job_templates/install_errata_by_search_query.erb +1 -1
  84. data/app/views/foreman/job_templates/install_errata_by_search_query_-_katello_ansible_default.erb +1 -1
  85. data/app/views/katello/api/v2/flatpak_remote_repositories/base.json.rabl +3 -1
  86. data/app/views/katello/api/v2/flatpak_remotes/base.json.rabl +5 -0
  87. data/app/views/katello/api/v2/flatpak_remotes/permissions.json.rabl +1 -0
  88. data/config/routes/api/v2.rb +1 -1
  89. data/config/routes.rb +3 -0
  90. data/db/migrate/20250613210050_use_big_int_for_erratum_packages_id.rb +11 -0
  91. data/db/seeds.d/108-subcription-bookmarks.rb +2 -0
  92. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/content-hosts/views/content-hosts.html +1 -1
  93. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/errata/views/errata.html +5 -1
  94. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/i18n/bastion_katello.pot +4 -5
  95. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/i18n/locale/bn.po +6 -0
  96. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/i18n/locale/bn_IN.po +6 -0
  97. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/i18n/locale/ca.po +6 -0
  98. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/i18n/locale/cs_CZ.po +6 -0
  99. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/i18n/locale/de.po +6 -0
  100. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/i18n/locale/de_AT.po +6 -0
  101. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/i18n/locale/de_DE.po +6 -0
  102. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/i18n/locale/el.po +6 -0
  103. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/i18n/locale/en_GB.po +6 -0
  104. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/i18n/locale/en_US.po +6 -0
  105. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/i18n/locale/es.po +6 -0
  106. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/i18n/locale/et_EE.po +6 -0
  107. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/i18n/locale/fr.po +6 -0
  108. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/i18n/locale/gl.po +6 -0
  109. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/i18n/locale/gu.po +6 -0
  110. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/i18n/locale/he_IL.po +6 -0
  111. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/i18n/locale/hi.po +6 -0
  112. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/i18n/locale/id.po +6 -0
  113. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/i18n/locale/it.po +6 -0
  114. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/i18n/locale/ja.po +6 -0
  115. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/i18n/locale/ka.po +6 -0
  116. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/i18n/locale/kn.po +6 -0
  117. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/i18n/locale/ko.po +6 -0
  118. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/i18n/locale/ml_IN.po +6 -0
  119. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/i18n/locale/mr.po +6 -0
  120. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/i18n/locale/nl_NL.po +6 -0
  121. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/i18n/locale/or.po +6 -0
  122. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/i18n/locale/pa.po +6 -0
  123. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/i18n/locale/pl.po +6 -0
  124. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/i18n/locale/pl_PL.po +6 -0
  125. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/i18n/locale/pt.po +6 -0
  126. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/i18n/locale/pt_BR.po +6 -0
  127. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/i18n/locale/ro.po +6 -0
  128. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/i18n/locale/ro_RO.po +6 -0
  129. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/i18n/locale/ru.po +6 -0
  130. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/i18n/locale/sl.po +6 -0
  131. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/i18n/locale/sv_SE.po +6 -0
  132. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/i18n/locale/ta.po +6 -0
  133. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/i18n/locale/ta_IN.po +6 -0
  134. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/i18n/locale/te.po +6 -0
  135. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/i18n/locale/tr.po +6 -0
  136. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/i18n/locale/vi.po +6 -0
  137. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/i18n/locale/vi_VN.po +6 -0
  138. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/i18n/locale/zh.po +6 -0
  139. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/i18n/locale/zh_CN.po +6 -0
  140. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/i18n/locale/zh_TW.po +6 -0
  141. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/products/details/repositories/new/new-repository.controller.js +13 -3
  142. data/engines/bastion_katello/lib/bastion_katello/engine.rb +2 -0
  143. data/lib/katello/engine.rb +0 -1
  144. data/lib/katello/permission_creator.rb +1 -1
  145. data/lib/katello/plugin.rb +26 -2
  146. data/lib/katello/version.rb +1 -1
  147. data/lib/katello.rb +0 -1
  148. data/lib/proxy_api/container_gateway.rb +24 -0
  149. data/locale/bn/LC_MESSAGES/katello.mo +0 -0
  150. data/locale/bn/katello.po +148 -4
  151. data/locale/bn_IN/LC_MESSAGES/katello.mo +0 -0
  152. data/locale/bn_IN/katello.po +148 -4
  153. data/locale/ca/LC_MESSAGES/katello.mo +0 -0
  154. data/locale/ca/katello.po +148 -4
  155. data/locale/cs/LC_MESSAGES/katello.mo +0 -0
  156. data/locale/cs/katello.po +148 -4
  157. data/locale/cs_CZ/LC_MESSAGES/katello.mo +0 -0
  158. data/locale/cs_CZ/katello.po +148 -4
  159. data/locale/de/katello.po +147 -3
  160. data/locale/de_AT/LC_MESSAGES/katello.mo +0 -0
  161. data/locale/de_AT/katello.po +148 -4
  162. data/locale/de_DE/LC_MESSAGES/katello.mo +0 -0
  163. data/locale/de_DE/katello.po +148 -4
  164. data/locale/el/LC_MESSAGES/katello.mo +0 -0
  165. data/locale/el/katello.po +148 -4
  166. data/locale/en/LC_MESSAGES/katello.mo +0 -0
  167. data/locale/en/katello.po +148 -4
  168. data/locale/en_GB/LC_MESSAGES/katello.mo +0 -0
  169. data/locale/en_GB/katello.po +148 -4
  170. data/locale/en_US/LC_MESSAGES/katello.mo +0 -0
  171. data/locale/en_US/katello.po +148 -4
  172. data/locale/es/katello.po +147 -3
  173. data/locale/et_EE/LC_MESSAGES/katello.mo +0 -0
  174. data/locale/et_EE/katello.po +148 -4
  175. data/locale/fr/katello.po +147 -3
  176. data/locale/gl/LC_MESSAGES/katello.mo +0 -0
  177. data/locale/gl/katello.po +148 -4
  178. data/locale/gu/LC_MESSAGES/katello.mo +0 -0
  179. data/locale/gu/katello.po +148 -4
  180. data/locale/he_IL/LC_MESSAGES/katello.mo +0 -0
  181. data/locale/he_IL/katello.po +148 -4
  182. data/locale/hi/LC_MESSAGES/katello.mo +0 -0
  183. data/locale/hi/katello.po +148 -4
  184. data/locale/id/LC_MESSAGES/katello.mo +0 -0
  185. data/locale/id/katello.po +148 -4
  186. data/locale/it/LC_MESSAGES/katello.mo +0 -0
  187. data/locale/it/katello.po +148 -4
  188. data/locale/ja/katello.po +147 -3
  189. data/locale/ka/katello.po +147 -3
  190. data/locale/katello.pot +703 -428
  191. data/locale/kn/LC_MESSAGES/katello.mo +0 -0
  192. data/locale/kn/katello.po +148 -4
  193. data/locale/ko/katello.po +147 -3
  194. data/locale/ml_IN/LC_MESSAGES/katello.mo +0 -0
  195. data/locale/ml_IN/katello.po +148 -4
  196. data/locale/mr/LC_MESSAGES/katello.mo +0 -0
  197. data/locale/mr/katello.po +148 -4
  198. data/locale/nl_NL/LC_MESSAGES/katello.mo +0 -0
  199. data/locale/nl_NL/katello.po +148 -4
  200. data/locale/or/LC_MESSAGES/katello.mo +0 -0
  201. data/locale/or/katello.po +148 -4
  202. data/locale/pa/LC_MESSAGES/katello.mo +0 -0
  203. data/locale/pa/katello.po +148 -4
  204. data/locale/pl/LC_MESSAGES/katello.mo +0 -0
  205. data/locale/pl/katello.po +148 -4
  206. data/locale/pl_PL/LC_MESSAGES/katello.mo +0 -0
  207. data/locale/pl_PL/katello.po +148 -4
  208. data/locale/pt/LC_MESSAGES/katello.mo +0 -0
  209. data/locale/pt/katello.po +148 -4
  210. data/locale/pt_BR/katello.po +147 -3
  211. data/locale/ro/LC_MESSAGES/katello.mo +0 -0
  212. data/locale/ro/katello.po +148 -4
  213. data/locale/ro_RO/LC_MESSAGES/katello.mo +0 -0
  214. data/locale/ro_RO/katello.po +148 -4
  215. data/locale/ru/LC_MESSAGES/katello.mo +0 -0
  216. data/locale/ru/katello.po +148 -4
  217. data/locale/sl/LC_MESSAGES/katello.mo +0 -0
  218. data/locale/sl/katello.po +148 -4
  219. data/locale/sv_SE/LC_MESSAGES/katello.mo +0 -0
  220. data/locale/sv_SE/katello.po +148 -4
  221. data/locale/ta/LC_MESSAGES/katello.mo +0 -0
  222. data/locale/ta/katello.po +148 -4
  223. data/locale/ta_IN/LC_MESSAGES/katello.mo +0 -0
  224. data/locale/ta_IN/katello.po +148 -4
  225. data/locale/te/LC_MESSAGES/katello.mo +0 -0
  226. data/locale/te/katello.po +148 -4
  227. data/locale/tr/LC_MESSAGES/katello.mo +0 -0
  228. data/locale/tr/katello.po +148 -4
  229. data/locale/vi/LC_MESSAGES/katello.mo +0 -0
  230. data/locale/vi/katello.po +148 -4
  231. data/locale/vi_VN/LC_MESSAGES/katello.mo +0 -0
  232. data/locale/vi_VN/katello.po +148 -4
  233. data/locale/zh/LC_MESSAGES/katello.mo +0 -0
  234. data/locale/zh/katello.po +148 -4
  235. data/locale/zh_CN/katello.po +147 -3
  236. data/locale/zh_TW/LC_MESSAGES/katello.mo +0 -0
  237. data/locale/zh_TW/katello.po +148 -4
  238. data/package.json +0 -1
  239. data/webpack/components/Content/Details/__tests__/__snapshots__/ContentDetails.test.js.snap +2 -2
  240. data/webpack/components/OptionTooltip/OptionTooltip.scss +1 -1
  241. data/webpack/components/extensions/HostDetails/Tabs/PackagesTab/PackagesTab.js +6 -1
  242. data/webpack/components/extensions/Hosts/ActionsBar/index.js +11 -0
  243. data/webpack/components/extensions/Hosts/BulkActions/BulkChangeHostCVModal/BulkChangeHostCVModal.js +1 -1
  244. data/webpack/components/extensions/Hosts/BulkActions/BulkChangeHostCVModal/actions.js +1 -2
  245. data/webpack/components/extensions/Hosts/BulkActions/BulkErrataWizard/04_ReviewFooter.js +1 -1
  246. data/webpack/components/extensions/Hosts/BulkActions/BulkPackagesWizard/04_ReviewFooter.js +1 -1
  247. data/webpack/components/extensions/Hosts/BulkActions/BulkRepositorySetsWizard/01_BulkRepositorySetsTable.js +371 -0
  248. data/webpack/components/extensions/Hosts/BulkActions/BulkRepositorySetsWizard/03_Review.js +79 -0
  249. data/webpack/components/extensions/Hosts/BulkActions/BulkRepositorySetsWizard/03_ReviewFooter.js +73 -0
  250. data/webpack/components/extensions/Hosts/BulkActions/BulkRepositorySetsWizard/BulkRepositorySetsWizard.js +170 -0
  251. data/webpack/components/extensions/Hosts/BulkActions/BulkRepositorySetsWizard/actions.js +23 -0
  252. data/webpack/components/extensions/Hosts/BulkActions/BulkRepositorySetsWizard/helpers.js +28 -0
  253. data/webpack/components/extensions/Hosts/BulkActions/BulkRepositorySetsWizard/index.js +23 -0
  254. data/webpack/components/extensions/RegistrationCommands/fields/SetupContainerRegistryCerts.js +39 -0
  255. data/webpack/components/extensions/RegistrationCommands/index.js +7 -0
  256. data/webpack/components/pf3Table/formatters/ellipsisCellFormatter.js +3 -2
  257. data/webpack/containers/Application/config.js +11 -0
  258. data/webpack/global_index.js +3 -1
  259. data/webpack/scenes/FlatpakRemotes/CreateEdit/CreateFlatpakRemoteModal.js +30 -0
  260. data/webpack/scenes/FlatpakRemotes/CreateEdit/EditFlatpakRemotesModal.js +38 -0
  261. data/webpack/scenes/FlatpakRemotes/CreateEdit/FlatpakRemoteform.js +218 -0
  262. data/webpack/scenes/FlatpakRemotes/CreateEdit/__tests__/flatpakRemoteform.test.js +117 -0
  263. data/webpack/scenes/FlatpakRemotes/Delete/DeleteFlatpakModal.js +59 -0
  264. data/webpack/scenes/FlatpakRemotes/Details/FlatpakRemoteDetailActions.js +87 -0
  265. data/webpack/scenes/FlatpakRemotes/Details/FlatpakRemoteDetailReducers.js +23 -0
  266. data/webpack/scenes/FlatpakRemotes/Details/FlatpakRemoteDetailSelectors.js +16 -0
  267. data/webpack/scenes/FlatpakRemotes/Details/FlatpakRemoteDetails.js +167 -0
  268. data/webpack/scenes/FlatpakRemotes/Details/Mirror/MirrorRepositoryModal.js +135 -0
  269. data/webpack/scenes/FlatpakRemotes/Details/Mirror/__tests__/mirrorRepositoryModal.test.js +167 -0
  270. data/webpack/scenes/FlatpakRemotes/Details/RemoteRepositories/RemoteRepositoriesTable.js +171 -0
  271. data/webpack/scenes/FlatpakRemotes/Details/__tests__/flatpakRemoteDetails.fixtures.json +58 -0
  272. data/webpack/scenes/FlatpakRemotes/Details/__tests__/flatpakRemoteDetails.test.js +90 -0
  273. data/webpack/scenes/FlatpakRemotes/Details/index.js +4 -0
  274. data/webpack/scenes/FlatpakRemotes/FlatpakRemotesActions.js +26 -0
  275. data/webpack/scenes/FlatpakRemotes/FlatpakRemotesConstants.js +15 -0
  276. data/webpack/scenes/FlatpakRemotes/FlatpakRemotesPage.js +202 -0
  277. data/webpack/scenes/FlatpakRemotes/FlatpakRemotesSelectors.js +24 -0
  278. data/webpack/scenes/FlatpakRemotes/__tests__/flatpakRemotesList.fixtures.json +55 -0
  279. data/webpack/scenes/FlatpakRemotes/__tests__/flatpakRemotesPage.test.js +74 -0
  280. data/webpack/scenes/FlatpakRemotes/index.js +4 -0
  281. data/webpack/scenes/Hosts/ChangeContentSource/components/Hosts.js +2 -2
  282. data/webpack/scenes/RedHatRepositories/components/RecommendedRepositorySetsToggler.scss +1 -1
  283. data/webpack/scenes/RedHatRepositories/index.scss +1 -1
  284. data/webpack/scenes/Settings/SettingsSelectors.js +3 -3
  285. data/webpack/scenes/Settings/index.js +1 -3
  286. data/webpack/scenes/Subscriptions/Details/__tests__/__snapshots__/SubscriptionDetails.test.js.snap +2 -2
  287. data/webpack/scenes/Subscriptions/SubscriptionsPage.scss +1 -1
  288. data/webpack/scenes/Subscriptions/__tests__/SubscriptionsReducer.test.js +0 -21
  289. data/webpack/scenes/Subscriptions/__tests__/__snapshots__/SubscriptionsReducer.test.js.snap +0 -44
  290. data/webpack/scenes/Subscriptions/index.js +1 -3
  291. metadata +38 -21
  292. data/webpack/scenes/Settings/SettingsConstants.js +0 -2
  293. data/webpack/scenes/Settings/SettingsReducer.js +0 -19
@@ -0,0 +1,23 @@
1
+ import { translate as __ } from 'foremanReact/common/I18n';
2
+ import { API_OPERATIONS, put } from 'foremanReact/redux/API';
3
+ import { errorToast, renderTaskStartedToast } from '../../../../../scenes/Tasks/helpers';
4
+ import { foremanApi } from '../../../../../services/api';
5
+
6
+ const BULK_HOST_CONTENT_OVERRIDES_KEY = 'BULK_HOST_CONTENT_OVERRIDES';
7
+
8
+ export const bulkUpdateHostContentOverrides =
9
+ (params, handleSuccess, handleError) => put({
10
+ type: API_OPERATIONS.PUT,
11
+ key: BULK_HOST_CONTENT_OVERRIDES_KEY,
12
+ url: foremanApi.getApiUrl('/hosts/bulk/content_overrides'),
13
+ successToast: () => __('Content overrides updating.'),
14
+ handleSuccess: (response) => {
15
+ if (handleSuccess) handleSuccess(response);
16
+ return renderTaskStartedToast(response.data);
17
+ },
18
+ handleError,
19
+ errorToast,
20
+ params,
21
+ });
22
+
23
+ export default bulkUpdateHostContentOverrides;
@@ -0,0 +1,28 @@
1
+ export const pendingOverrideToApiParamItem = ({ repoLabel, value }) => {
2
+ switch (Number(value)) {
3
+ case 0: // No change
4
+ return null;
5
+ case 1: // Override to enabled
6
+ return {
7
+ content_label: repoLabel,
8
+ name: 'enabled',
9
+ value: true,
10
+ };
11
+ case 2: // Override to disabled
12
+ return {
13
+ content_label: repoLabel,
14
+ name: 'enabled',
15
+ value: false,
16
+ };
17
+ case 3: // Reset to default
18
+ return {
19
+ content_label: repoLabel,
20
+ name: 'enabled',
21
+ remove: true,
22
+ };
23
+ default:
24
+ return null;
25
+ }
26
+ };
27
+
28
+ export default pendingOverrideToApiParamItem;
@@ -0,0 +1,23 @@
1
+ import React from 'react';
2
+ import { Modal, ModalVariant } from '@patternfly/react-core';
3
+ import { useForemanModal } from 'foremanReact/components/ForemanModal/ForemanModalHooks';
4
+ import BulkRepositorySetsWizard from './BulkRepositorySetsWizard';
5
+
6
+ const BulkRepositorySetsWizardModal = () => {
7
+ const { modalOpen: isOpen } = useForemanModal({ id: 'bulk-repo-sets-wizard' });
8
+
9
+ return (
10
+ <Modal
11
+ ouiaId="bulk-repo-sets-wizard-modal"
12
+ isOpen={isOpen}
13
+ showClose={false}
14
+ aria-label="Wizard modal"
15
+ hasNoBodyWrapper
16
+ variant={ModalVariant.large}
17
+ >
18
+ <BulkRepositorySetsWizard />
19
+ </Modal>
20
+ );
21
+ };
22
+
23
+ export default BulkRepositorySetsWizardModal;
@@ -0,0 +1,39 @@
1
+ import React from 'react';
2
+ import PropTypes from 'prop-types';
3
+ import { noop } from 'foremanReact/common/helpers';
4
+
5
+ import { FormGroup, Checkbox } from '@patternfly/react-core';
6
+ import LabelIcon from 'foremanReact/components/common/LabelIcon';
7
+ import { translate as __ } from 'foremanReact/common/I18n';
8
+
9
+ const SetupContainerRegistryCerts = ({ value, onChange, isLoading }) => (
10
+ <FormGroup fieldId="reg_container_certs">
11
+ <Checkbox
12
+ ouiaId="reg-container-certs"
13
+ label={
14
+ <span>
15
+ {__('Set up container registry certs')}{' '}
16
+ <LabelIcon text={__('Place symlinks to entitlement certificates on the host, enabling container/flatpak registry access without a username or password.')} />
17
+ </span>
18
+ }
19
+ id="reg_container_certs"
20
+ onChange={() => onChange({ setupContainerRegistryCerts: !value })}
21
+ isDisabled={isLoading}
22
+ isChecked={value}
23
+ />
24
+ </FormGroup>
25
+ );
26
+
27
+ SetupContainerRegistryCerts.propTypes = {
28
+ value: PropTypes.bool,
29
+ onChange: PropTypes.func,
30
+ isLoading: PropTypes.bool,
31
+ };
32
+
33
+ SetupContainerRegistryCerts.defaultProps = {
34
+ value: false,
35
+ onChange: noop,
36
+ isLoading: false,
37
+ };
38
+
39
+ export default SetupContainerRegistryCerts;
@@ -7,6 +7,7 @@ import { determineInitialAKSelection } from './helpers';
7
7
  import ActivationKeys from './fields/ActivationKeys';
8
8
  import IgnoreSubmanErrors from './fields/IgnoreSubmanErrors';
9
9
  import Force from './fields/Force';
10
+ import SetupContainerRegistryCerts from './fields/SetupContainerRegistryCerts';
10
11
 
11
12
  export const RegistrationCommands = ({
12
13
  pluginValues,
@@ -26,6 +27,12 @@ export const RegistrationCommands = ({
26
27
  onChange={onChange}
27
28
  isLoading={isLoading}
28
29
  />
30
+ <SetupContainerRegistryCerts
31
+ value={pluginValues?.setupContainerRegistryCerts}
32
+ pluginValues={pluginValues}
33
+ onChange={onChange}
34
+ isLoading={isLoading}
35
+ />
29
36
  </>
30
37
  );
31
38
 
@@ -1,5 +1,6 @@
1
1
  import React from 'react';
2
- import EllipsisWithTooltip from 'react-ellipsis-with-tooltip';
2
+ import { Truncate } from '@patternfly/react-core';
3
+
3
4
  import cellFormatter from './cellFormatter';
4
5
 
5
- export default value => cellFormatter(<EllipsisWithTooltip>{value}</EllipsisWithTooltip>);
6
+ export default value => cellFormatter(<Truncate content={value} />);
@@ -16,6 +16,8 @@ import withHeader from './withHeaders';
16
16
  import ChangeContentSource from '../../scenes/Hosts/ChangeContentSource';
17
17
  import AlternateContentSource from '../../scenes/AlternateContentSources';
18
18
  import BootedContainerImages from '../../scenes/BootedContainerImages';
19
+ import FlatpakRemotes from '../../scenes/FlatpakRemotes';
20
+ import FlatpakRemoteDetails from '../../scenes/FlatpakRemotes/Details';
19
21
 
20
22
  // eslint-disable-next-line import/prefer-default-export
21
23
  export const links = [
@@ -90,4 +92,13 @@ export const links = [
90
92
  path: 'booted_container_images',
91
93
  component: WithOrganization(withHeader(BootedContainerImages, { title: __('Booted container images') })),
92
94
  },
95
+ {
96
+ path: 'flatpak_remotes',
97
+ component: WithOrganization(withHeader(FlatpakRemotes, { title: __('Flatpak Remotes') })),
98
+ },
99
+ {
100
+ path: 'flatpak_remotes/:id([0-9]+)',
101
+ component: WithOrganization(withHeader(FlatpakRemoteDetails, { title: __('Flatpak Remote Details') })),
102
+ exact: false,
103
+ },
93
104
  ];
@@ -38,6 +38,7 @@ import SystemPurposeCard from './components/extensions/HostDetails/Cards/SystemP
38
38
  import BulkChangeHostCVModal from './components/extensions/Hosts/BulkActions/BulkChangeHostCVModal/index.js';
39
39
  import BulkPackagesWizardModal from './components/extensions/Hosts/BulkActions/BulkPackagesWizard/index.js';
40
40
  import BulkErrataWizardModal from './components/extensions/Hosts/BulkActions/BulkErrataWizard/index.js';
41
+ import BulkRepositorySetsWizardModal from './components/extensions/Hosts/BulkActions/BulkRepositorySetsWizard/index.js';
41
42
  import ActivationKeysSearch from './components/ActivationKeysSearch';
42
43
  import { CVEDetailsCard } from './scenes/ActivationKeys/Details/components/CVEDetailsCard.js';
43
44
 
@@ -96,7 +97,8 @@ addGlobalFill(
96
97
  // Hosts Index page extensions
97
98
  addGlobalFill('_all-hosts-modals', 'BulkChangeHostCVModal', <BulkChangeHostCVModal key="bulk-change-host-cv-modal" />, 100);
98
99
  addGlobalFill('_all-hosts-modals', 'BulkPackagesWizardModal', <BulkPackagesWizardModal key="bulk-packages-wizard-modal" />, 200);
99
- addGlobalFill('_all-hosts-modals', 'BulkErrataWizardModal', <BulkErrataWizardModal key="bulk-errata-wizard-modal" />, 200);
100
+ addGlobalFill('_all-hosts-modals', 'BulkErrataWizardModal', <BulkErrataWizardModal key="bulk-errata-wizard-modal" />, 300);
101
+ addGlobalFill('_all-hosts-modals', 'BulkRepositorySetsWizardModal', <BulkRepositorySetsWizardModal key="bulk-repo-sets-wizard-modal" />, 400);
100
102
 
101
103
  registerColumns(hostsIndexColumnExtensions);
102
104
  registerGetActions({
@@ -0,0 +1,30 @@
1
+ import React from 'react';
2
+ import PropTypes from 'prop-types';
3
+ import { translate as __ } from 'foremanReact/common/I18n';
4
+ import { Modal, ModalVariant } from '@patternfly/react-core';
5
+ import FlatpakRemotesForm from './FlatpakRemoteform';
6
+
7
+ const CreateFlatpakModal = ({ show, setIsOpen }) => (
8
+ <Modal
9
+ ouiaId="create-flatpak-modal"
10
+ title={__('Create Flatpak Remote')}
11
+ variant={ModalVariant.small}
12
+ isOpen={show}
13
+ onClose={() => { setIsOpen(false); }}
14
+ appendTo={document.body}
15
+ >
16
+ <FlatpakRemotesForm setModalOpen={setIsOpen} />
17
+ </Modal>
18
+ );
19
+
20
+ CreateFlatpakModal.propTypes = {
21
+ show: PropTypes.bool,
22
+ setIsOpen: PropTypes.func,
23
+ };
24
+
25
+ CreateFlatpakModal.defaultProps = {
26
+ show: false,
27
+ setIsOpen: null,
28
+ };
29
+
30
+ export default CreateFlatpakModal;
@@ -0,0 +1,38 @@
1
+ import React from 'react';
2
+ import PropTypes from 'prop-types';
3
+ import { translate as __ } from 'foremanReact/common/I18n';
4
+ import { Modal, ModalVariant } from '@patternfly/react-core';
5
+ import FlatpakRemotesForm from './FlatpakRemoteform';
6
+
7
+ const EditFlatpakModal = ({ show, setIsOpen, remoteData }) => (
8
+ <Modal
9
+ ouiaId="edit-flatpak-modal"
10
+ title={__('Edit Flatpak Remote')}
11
+ variant={ModalVariant.small}
12
+ isOpen={show}
13
+ onClose={() => { setIsOpen(false); }}
14
+ appendTo={document.body}
15
+ >
16
+ <FlatpakRemotesForm setModalOpen={setIsOpen} remoteData={remoteData} />
17
+ </Modal>
18
+ );
19
+
20
+ EditFlatpakModal.propTypes = {
21
+ show: PropTypes.bool,
22
+ setIsOpen: PropTypes.func,
23
+ remoteData: PropTypes.shape({
24
+ id: PropTypes.number,
25
+ name: PropTypes.string,
26
+ url: PropTypes.string,
27
+ username: PropTypes.string,
28
+ password: PropTypes.string,
29
+ }),
30
+ };
31
+
32
+ EditFlatpakModal.defaultProps = {
33
+ show: false,
34
+ setIsOpen: null,
35
+ remoteData: null,
36
+ };
37
+
38
+ export default EditFlatpakModal;
@@ -0,0 +1,218 @@
1
+ import React, { useState } from 'react';
2
+ import useDeepCompareEffect from 'use-deep-compare-effect';
3
+ import { STATUS } from 'foremanReact/constants';
4
+ import { translate as __ } from 'foremanReact/common/I18n';
5
+ import PropTypes from 'prop-types';
6
+ import { useDispatch, useSelector } from 'react-redux';
7
+ import {
8
+ Form,
9
+ FormGroup,
10
+ TextInput,
11
+ ActionGroup,
12
+ Button,
13
+ FormHelperText,
14
+ HelperText,
15
+ HelperTextItem,
16
+
17
+ } from '@patternfly/react-core';
18
+ import { createFlatpakRemote } from '../FlatpakRemotesActions';
19
+ import {
20
+ selectCreateFlatpakRemotes,
21
+ selectCreateFlatpakRemotesStatus,
22
+ selectCreateFlatpakRemotesError,
23
+ } from '../FlatpakRemotesSelectors';
24
+ import { updateFlatpakRemote } from '../Details/FlatpakRemoteDetailActions';
25
+
26
+ // eslint-disable-next-line react/prop-types
27
+ const FlatpakRemotesForm = ({ setModalOpen, remoteData }) => {
28
+ const {
29
+ id: editingId,
30
+ name: editingName,
31
+ url: editingUrl,
32
+ username: editingUsername,
33
+ upstream_password_exists: passwordExists,
34
+ } = remoteData || {};
35
+
36
+ const isEditing = !!editingName;
37
+ const dispatch = useDispatch();
38
+ const [name, setName] = useState(editingName || '');
39
+ const [url, setUrl] = useState(editingUrl || '');
40
+ const [username, setUsername] = useState(editingUsername || '');
41
+ const [password, setPassword] = useState(passwordExists ? '*****' : '');
42
+ const [redirect, setRedirect] = useState(false);
43
+ const [saving, setSaving] = useState(false);
44
+
45
+ const [urlValidated, setUrlValidated] = useState('default');
46
+ const handleUrlChange = (newurl, _event) => {
47
+ setUrl(newurl);
48
+ if (newurl === '') {
49
+ setUrlValidated('default');
50
+ } else if (/^(http(s)?:\/\/)[-a-zA-Z0-9@:%._~#=]{2,256}\.[a-z]{2,6}\b([-a-zA-Z0-9@:%_.~#?&//=]*)$/g.test(newurl)) {
51
+ setUrlValidated('success');
52
+ } else {
53
+ setUrlValidated('error');
54
+ }
55
+ };
56
+
57
+ const response = useSelector(selectCreateFlatpakRemotes);
58
+ const status = useSelector(selectCreateFlatpakRemotesStatus);
59
+ const error = useSelector(selectCreateFlatpakRemotesError);
60
+
61
+ useDeepCompareEffect(() => {
62
+ const { id } = response;
63
+ if (id && status === STATUS.RESOLVED && saving) {
64
+ setSaving(false);
65
+ setRedirect(true);
66
+ } else if (status === STATUS.ERROR) {
67
+ setSaving(false);
68
+ }
69
+ }, [response, status, error, saving]);
70
+
71
+ const onSave = () => {
72
+ setSaving(true);
73
+ let editingParams = {};
74
+ if (isEditing && password === '*****') {
75
+ editingParams = {
76
+ name,
77
+ url,
78
+ username,
79
+ };
80
+ } else {
81
+ editingParams = {
82
+ name,
83
+ url,
84
+ username,
85
+ token: password,
86
+ };
87
+ }
88
+ dispatch(isEditing ?
89
+ updateFlatpakRemote(
90
+ editingId, editingParams, () => window.location.assign(`/flatpak_remotes/${editingId}`),
91
+ () => setModalOpen(false),
92
+ ) :
93
+ createFlatpakRemote({
94
+ name,
95
+ url,
96
+ username,
97
+ token: password,
98
+ }));
99
+ };
100
+
101
+ if (redirect) {
102
+ const { id } = response;
103
+ window.location.assign(`/flatpak_remotes/${id}`);
104
+ }
105
+
106
+ const submitDisabled =
107
+ !name?.length || !url?.length || saving || redirect || urlValidated === 'error';
108
+
109
+ return (
110
+ <Form
111
+ onSubmit={(e) => {
112
+ e.preventDefault();
113
+ onSave();
114
+ }}
115
+ id="create-flatpak-form"
116
+ >
117
+ <FormGroup
118
+ label={__('Name')}
119
+ isRequired
120
+ fieldId="name"
121
+ >
122
+ <TextInput
123
+ isRequired
124
+ type="text"
125
+ id="name"
126
+ aria-label="input_name"
127
+ ouiaId="input_name"
128
+ name="name"
129
+ value={name}
130
+ onChange={(_event, value) => setName(value)}
131
+ />
132
+ </FormGroup>
133
+ <FormGroup
134
+ label={__('URL')}
135
+ isRequired
136
+ fieldId="url"
137
+ >
138
+ <TextInput
139
+ isRequired
140
+ type="url"
141
+ id="url"
142
+ aria-label="input_url"
143
+ ouiaId="input_url"
144
+ name="url"
145
+ value={url}
146
+ validated={urlValidated}
147
+ onChange={(_event, newurl) => handleUrlChange(newurl, _event)}
148
+ />
149
+ {urlValidated === 'error' && (
150
+ <FormHelperText>
151
+ <HelperText>
152
+ <HelperTextItem variant="error">
153
+ {__('Must be a vaild URL')}
154
+ </HelperTextItem>
155
+ </HelperText>
156
+ </FormHelperText>
157
+ )}
158
+ </FormGroup>
159
+ <FormGroup label={__('Username')} fieldId="username">
160
+ <TextInput
161
+ type="text"
162
+ id="username"
163
+ ouiaId="input_username"
164
+ name="username"
165
+ aria-label="input_username"
166
+ value={username}
167
+ onChange={(_event, value) => setUsername(value)}
168
+ />
169
+ <FormHelperText>
170
+ <HelperText>
171
+ <HelperTextItem>Authentication for registry</HelperTextItem>
172
+ </HelperText>
173
+ </FormHelperText>
174
+ </FormGroup>
175
+ <FormGroup label={__('Password')} fieldId="password">
176
+ <TextInput
177
+ type="password"
178
+ id="password"
179
+ ouiaId="input_password"
180
+ name="password"
181
+ aria-label="input_password"
182
+ value={password}
183
+ onChange={(_event, value) => setPassword(value)}
184
+ />
185
+ </FormGroup>
186
+
187
+ <ActionGroup>
188
+ <Button
189
+ ouiaId="create-flatpak-form-submit"
190
+ aria-label="create_flatpak"
191
+ variant="primary"
192
+ isDisabled={submitDisabled}
193
+ isLoading={saving || redirect}
194
+ type="submit"
195
+ >
196
+ {isEditing ? __('Update') : __('Create')}
197
+ </Button>
198
+ <Button
199
+ ouiaId="create-flatpakcancel"
200
+ variant="link"
201
+ onClick={() => setModalOpen(false)}
202
+ >
203
+ {__('Cancel')}
204
+ </Button>
205
+ </ActionGroup>
206
+ </Form>
207
+ );
208
+ };
209
+
210
+ FlatpakRemotesForm.propTypes = {
211
+ setModalOpen: PropTypes.func,
212
+ };
213
+
214
+ FlatpakRemotesForm.defaultProps = {
215
+ setModalOpen: null,
216
+ };
217
+
218
+ export default FlatpakRemotesForm;
@@ -0,0 +1,117 @@
1
+ import React from 'react';
2
+ import { renderWithRedux, patientlyWaitFor, fireEvent } from 'react-testing-lib-wrapper';
3
+ import { nockInstance, assertNockRequest } from '../../../../test-utils/nockWrapper';
4
+ import FlatpakRemotesForm from '../FlatpakRemoteform';
5
+ import api from '../../../../services/api';
6
+
7
+ const mockFn = jest.fn();
8
+ delete window.location;
9
+ window.location = { assign: mockFn };
10
+
11
+ afterEach(() => {
12
+ mockFn.mockClear();
13
+ });
14
+
15
+ const createFlatpakPath = api.getApiUrl('/flatpak_remotes');
16
+ const updateFlatpakPath = id => api.getApiUrl(`/flatpak_remotes/${id}`);
17
+
18
+ const mockRemoteData = {
19
+ id: 1,
20
+ name: 'Test Remote',
21
+ url: 'https://example.com',
22
+ username: 'testuser',
23
+ upstream_password_exists: true,
24
+ };
25
+
26
+ test('Renders FlatpakRemotesForm fields correctly', () => {
27
+ const { getByText } = renderWithRedux(<FlatpakRemotesForm setModalOpen={mockFn} />);
28
+ expect(getByText('Name')).toBeInTheDocument();
29
+ expect(getByText('URL')).toBeInTheDocument();
30
+ expect(getByText('Username')).toBeInTheDocument();
31
+ expect(getByText('Password')).toBeInTheDocument();
32
+ });
33
+
34
+ test('Can save Flatpak remote from form', async (done) => {
35
+ const createScope = nockInstance
36
+ .post(createFlatpakPath, {
37
+ organization_id: 1,
38
+ name: 'New Remote',
39
+ url: 'https://example.com',
40
+ username: 'testuser',
41
+ token: 'password123',
42
+ })
43
+ .reply(201, { id: 2 });
44
+
45
+ const { getByLabelText, getByText } = renderWithRedux(<FlatpakRemotesForm
46
+ setModalOpen={mockFn}
47
+ />);
48
+ fireEvent.change(getByLabelText('input_name'), { target: { value: 'New Remote' } });
49
+ fireEvent.change(getByLabelText('input_url'), { target: { value: 'https://example.com' } });
50
+ fireEvent.change(getByLabelText('input_username'), { target: { value: 'testuser' } });
51
+ fireEvent.change(getByLabelText('input_password'), { target: { value: 'password123' } });
52
+
53
+ getByText('Create').click();
54
+
55
+ await patientlyWaitFor(() => {
56
+ expect(window.location.assign).toHaveBeenCalledWith('/flatpak_remotes/2');
57
+ });
58
+
59
+ assertNockRequest(createScope);
60
+ done();
61
+ });
62
+
63
+ test('Can update Flatpak remote from form', async (done) => {
64
+ const updateScope = nockInstance
65
+ .put(updateFlatpakPath(mockRemoteData.id), {
66
+ name: 'Updated Remote',
67
+ url: 'https://updated.com',
68
+ username: 'updateduser',
69
+ })
70
+ .reply(200);
71
+
72
+ const { getByLabelText, getByText } = renderWithRedux(<FlatpakRemotesForm
73
+ setModalOpen={mockFn}
74
+ remoteData={mockRemoteData}
75
+ />);
76
+
77
+ fireEvent.change(getByLabelText('input_name'), { target: { value: 'Updated Remote' } });
78
+ fireEvent.change(getByLabelText('input_url'), { target: { value: 'https://updated.com' } });
79
+ fireEvent.change(getByLabelText('input_username'), { target: { value: 'updateduser' } });
80
+
81
+ getByText('Update').click();
82
+
83
+ await patientlyWaitFor(() => {
84
+ expect(window.location.assign).toHaveBeenCalledWith('/flatpak_remotes/1');
85
+ });
86
+
87
+ assertNockRequest(updateScope);
88
+ done();
89
+ });
90
+
91
+ test('Can update Flatpak remote password from placeholder', async (done) => {
92
+ const updateScope = nockInstance
93
+ .put(updateFlatpakPath(mockRemoteData.id), {
94
+ name: mockRemoteData.name,
95
+ url: mockRemoteData.url,
96
+ username: mockRemoteData.username,
97
+ token: 'newpassword123',
98
+ })
99
+ .reply(200);
100
+
101
+ const { getByLabelText, getByText } = renderWithRedux(<FlatpakRemotesForm
102
+ setModalOpen={mockFn}
103
+ remoteData={mockRemoteData}
104
+ />);
105
+
106
+ // Simulate changing the password from the placeholder to a new value
107
+ fireEvent.change(getByLabelText('input_password'), { target: { value: 'newpassword123' } });
108
+
109
+ getByText('Update').click();
110
+
111
+ await patientlyWaitFor(() => {
112
+ expect(window.location.assign).toHaveBeenCalledWith('/flatpak_remotes/1');
113
+ });
114
+
115
+ assertNockRequest(updateScope);
116
+ done();
117
+ });
@@ -0,0 +1,59 @@
1
+ import React from 'react';
2
+ import { useDispatch } from 'react-redux';
3
+ import PropTypes from 'prop-types';
4
+ import { Modal, ModalVariant, Button, Icon, Title, Flex } from '@patternfly/react-core';
5
+ import { ExclamationTriangleIcon } from '@patternfly/react-icons';
6
+ import { translate as __ } from 'foremanReact/common/I18n';
7
+ import { deleteFlatpakRemote } from '../Details/FlatpakRemoteDetailActions';
8
+
9
+ const DeleteFlatpakModal = ({ isModalOpen, handleModalToggle, remoteId }) => {
10
+ const dispatch = useDispatch();
11
+
12
+ const handleDelete = () => {
13
+ dispatch(deleteFlatpakRemote(remoteId, () => window.location.replace('/flatpak_remotes')));
14
+ handleModalToggle();
15
+ };
16
+
17
+ return (
18
+ <Modal
19
+ ouiaId="flatpak-delete-modal"
20
+ variant={ModalVariant.small}
21
+ title={[
22
+ <Flex key="delete-modal-header">
23
+ <Icon status="warning" key="exclamation-triangle">
24
+ <ExclamationTriangleIcon />
25
+ </Icon>
26
+ <Title ouiaId="flatpak-delete-header" key="delete-flatpak-title" headingLevel="h5" size="2xl">
27
+ {__('Delete Flatpak remote?')}
28
+ </Title>
29
+ </Flex>,
30
+ ]}
31
+ isOpen={isModalOpen}
32
+ onClose={handleModalToggle}
33
+ actions={[
34
+ <Button ouiaId="delete-button" key="delete" variant="danger" onClick={handleDelete}>
35
+ {__('Delete')}
36
+ </Button>,
37
+ <Button ouiaId="cancel-button" key="cancel" variant="link" onClick={handleModalToggle}>
38
+ {__('Cancel')}
39
+ </Button>,
40
+ ]}
41
+ >
42
+ {__('This Flatpak remote will be deleted. Repositories mirrored from this remote will remain available and functional for use')}
43
+ </Modal>
44
+ );
45
+ };
46
+
47
+ DeleteFlatpakModal.propTypes = {
48
+ isModalOpen: PropTypes.bool,
49
+ handleModalToggle: PropTypes.func,
50
+ remoteId: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),
51
+ };
52
+
53
+ DeleteFlatpakModal.defaultProps = {
54
+ isModalOpen: false,
55
+ handleModalToggle: () => {},
56
+ remoteId: undefined,
57
+ };
58
+
59
+ export default DeleteFlatpakModal;