katello 4.18.0 → 4.19.0.rc1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of katello might be problematic. Click here for more details.
- checksums.yaml +4 -4
- data/app/assets/javascripts/katello/locale/bn/katello.js +52 -349
- data/app/assets/javascripts/katello/locale/bn_IN/katello.js +52 -349
- data/app/assets/javascripts/katello/locale/ca/katello.js +52 -349
- data/app/assets/javascripts/katello/locale/cs/katello.js +53 -350
- data/app/assets/javascripts/katello/locale/cs_CZ/katello.js +54 -351
- data/app/assets/javascripts/katello/locale/de/katello.js +56 -353
- data/app/assets/javascripts/katello/locale/de_AT/katello.js +52 -349
- data/app/assets/javascripts/katello/locale/de_DE/katello.js +52 -349
- data/app/assets/javascripts/katello/locale/el/katello.js +54 -351
- data/app/assets/javascripts/katello/locale/en/katello.js +53 -350
- data/app/assets/javascripts/katello/locale/en_GB/katello.js +53 -350
- data/app/assets/javascripts/katello/locale/en_US/katello.js +52 -349
- data/app/assets/javascripts/katello/locale/es/katello.js +56 -353
- data/app/assets/javascripts/katello/locale/et_EE/katello.js +52 -349
- data/app/assets/javascripts/katello/locale/fr/katello.js +138 -435
- data/app/assets/javascripts/katello/locale/gl/katello.js +52 -349
- data/app/assets/javascripts/katello/locale/gu/katello.js +52 -349
- data/app/assets/javascripts/katello/locale/he_IL/katello.js +52 -349
- data/app/assets/javascripts/katello/locale/hi/katello.js +52 -349
- data/app/assets/javascripts/katello/locale/id/katello.js +52 -349
- data/app/assets/javascripts/katello/locale/it/katello.js +53 -350
- data/app/assets/javascripts/katello/locale/ja/katello.js +142 -439
- data/app/assets/javascripts/katello/locale/ka/katello.js +56 -353
- data/app/assets/javascripts/katello/locale/kn/katello.js +52 -349
- data/app/assets/javascripts/katello/locale/ko/katello.js +135 -432
- data/app/assets/javascripts/katello/locale/ml_IN/katello.js +52 -349
- data/app/assets/javascripts/katello/locale/mr/katello.js +52 -349
- data/app/assets/javascripts/katello/locale/nl_NL/katello.js +52 -349
- data/app/assets/javascripts/katello/locale/or/katello.js +52 -349
- data/app/assets/javascripts/katello/locale/pa/katello.js +52 -349
- data/app/assets/javascripts/katello/locale/pl/katello.js +52 -349
- data/app/assets/javascripts/katello/locale/pl_PL/katello.js +52 -349
- data/app/assets/javascripts/katello/locale/pt/katello.js +52 -349
- data/app/assets/javascripts/katello/locale/pt_BR/katello.js +56 -353
- data/app/assets/javascripts/katello/locale/ro/katello.js +52 -349
- data/app/assets/javascripts/katello/locale/ro_RO/katello.js +52 -349
- data/app/assets/javascripts/katello/locale/ru/katello.js +54 -351
- data/app/assets/javascripts/katello/locale/sl/katello.js +52 -349
- data/app/assets/javascripts/katello/locale/sv_SE/katello.js +52 -349
- data/app/assets/javascripts/katello/locale/ta/katello.js +52 -349
- data/app/assets/javascripts/katello/locale/ta_IN/katello.js +52 -349
- data/app/assets/javascripts/katello/locale/te/katello.js +52 -349
- data/app/assets/javascripts/katello/locale/tr/katello.js +52 -349
- data/app/assets/javascripts/katello/locale/vi/katello.js +52 -349
- data/app/assets/javascripts/katello/locale/vi_VN/katello.js +52 -349
- data/app/assets/javascripts/katello/locale/zh/katello.js +52 -349
- data/app/assets/javascripts/katello/locale/zh_CN/katello.js +135 -432
- data/app/assets/javascripts/katello/locale/zh_TW/katello.js +54 -351
- data/app/controllers/katello/api/registry/registry_proxies_controller.rb +46 -13
- data/app/controllers/katello/api/rhsm/candlepin_proxies_controller.rb +1 -1
- data/app/controllers/katello/api/v2/activation_keys_controller.rb +3 -65
- data/app/controllers/katello/api/v2/content_export_incrementals_controller.rb +56 -34
- data/app/controllers/katello/api/v2/content_view_filter_rules_controller.rb +1 -1
- data/app/controllers/katello/api/v2/content_views_controller.rb +18 -3
- data/app/controllers/katello/api/v2/debs_controller.rb +21 -11
- data/app/controllers/katello/api/v2/docker_tags_controller.rb +7 -0
- data/app/controllers/katello/api/v2/errata_controller.rb +4 -4
- data/app/controllers/katello/api/v2/flatpak_remote_repositories_controller.rb +21 -19
- data/app/controllers/katello/api/v2/host_debs_controller.rb +16 -1
- data/app/controllers/katello/api/v2/host_subscriptions_controller.rb +3 -60
- data/app/controllers/katello/api/v2/hosts_bulk_actions_controller.rb +10 -53
- data/app/controllers/katello/api/v2/repositories_controller.rb +0 -1
- data/app/controllers/katello/concerns/organizations_controller_extensions.rb +3 -0
- data/app/lib/actions/candlepin/activation_key/create.rb +0 -2
- data/app/lib/actions/candlepin/activation_key/update.rb +0 -2
- data/app/lib/actions/candlepin/product/content_create.rb +3 -5
- data/app/lib/actions/candlepin/product/content_update.rb +2 -3
- data/app/lib/actions/helpers/rolling_cv_repos.rb +1 -1
- data/app/lib/actions/katello/activation_key/create.rb +0 -1
- data/app/lib/actions/katello/activation_key/update.rb +0 -2
- data/app/lib/actions/katello/capsule_content/sync_capsule.rb +1 -6
- data/app/lib/actions/katello/content_credential/update.rb +1 -1
- data/app/lib/actions/katello/content_view/add_rolling_repo_clone.rb +18 -24
- data/app/lib/actions/katello/content_view/create.rb +9 -4
- data/app/lib/actions/katello/content_view/publish.rb +7 -7
- data/app/lib/actions/katello/content_view/refresh_rolling_repo.rb +6 -1
- data/app/lib/actions/katello/content_view/remove_rolling_repo_clone.rb +16 -11
- data/app/lib/actions/katello/content_view/update.rb +34 -7
- data/app/lib/actions/katello/product/content_create.rb +2 -2
- data/app/lib/actions/katello/product/content_destroy.rb +1 -1
- data/app/lib/actions/katello/repository/check_matching_content.rb +1 -1
- data/app/lib/actions/katello/repository/clone_contents.rb +1 -1
- data/app/lib/actions/katello/repository/create.rb +1 -1
- data/app/lib/actions/katello/repository/destroy.rb +4 -4
- data/app/lib/actions/katello/repository/finish_upload.rb +1 -1
- data/app/lib/actions/katello/repository/sync.rb +1 -1
- data/app/lib/actions/pulp3/orchestration/repository/copy_all_units.rb +2 -2
- data/app/lib/actions/pulp3/orchestration/repository/generate_metadata.rb +1 -1
- data/app/lib/actions/pulp3/orchestration/repository/multi_copy_all_units.rb +1 -1
- data/app/lib/actions/pulp3/repository/save_publication.rb +3 -1
- data/app/lib/actions/pulp3/repository/save_version.rb +45 -24
- data/app/lib/actions/pulp3/repository/save_versions.rb +2 -1
- data/app/lib/katello/resources/candlepin/activation_key.rb +3 -4
- data/app/lib/katello/resources/candlepin/upstream_job.rb +9 -1
- data/app/lib/katello/resources/candlepin.rb +4 -0
- data/app/models/katello/authorization/repository.rb +17 -4
- data/app/models/katello/concerns/subscription_facet_host_extensions.rb +0 -7
- data/app/models/katello/content_view_deb_filter.rb +10 -0
- data/app/models/katello/content_view_deb_filter_rule.rb +7 -0
- data/app/models/katello/deb.rb +10 -12
- data/app/models/katello/erratum.rb +1 -1
- data/app/models/katello/glue/provider.rb +14 -3
- data/app/models/katello/host/content_facet.rb +1 -1
- data/app/models/katello/host/subscription_facet.rb +1 -7
- data/app/models/katello/product_content.rb +2 -2
- data/app/models/katello/repository.rb +4 -23
- data/app/models/katello/root_repository.rb +2 -5
- data/app/services/katello/candlepin/event_handler.rb +0 -33
- data/app/services/katello/candlepin/message_handler.rb +0 -41
- data/app/services/katello/content_unit_indexer.rb +59 -13
- data/app/services/katello/product_content_finder.rb +16 -7
- data/app/services/katello/pulp3/alternate_content_source.rb +2 -2
- data/app/services/katello/pulp3/ansible_collection.rb +1 -0
- data/app/services/katello/pulp3/api/content_guard.rb +5 -5
- data/app/services/katello/pulp3/api/core.rb +10 -0
- data/app/services/katello/pulp3/content_view_version/export.rb +25 -10
- data/app/services/katello/pulp3/deb.rb +1 -0
- data/app/services/katello/pulp3/docker_manifest.rb +1 -0
- data/app/services/katello/pulp3/docker_manifest_list.rb +1 -0
- data/app/services/katello/pulp3/docker_tag.rb +1 -0
- data/app/services/katello/pulp3/file_unit.rb +1 -0
- data/app/services/katello/pulp3/generic_content_unit.rb +1 -0
- data/app/services/katello/pulp3/module_stream.rb +1 -0
- data/app/services/katello/pulp3/package_group.rb +1 -0
- data/app/services/katello/pulp3/repository/apt.rb +30 -13
- data/app/services/katello/pulp3/repository.rb +59 -10
- data/app/services/katello/pulp3/rpm.rb +3 -2
- data/app/services/katello/pulp3/srpm.rb +3 -2
- data/app/services/katello/pulp3/task_group.rb +1 -1
- data/app/services/katello/registration_manager.rb +19 -17
- data/app/services/katello/repository_type_manager.rb +7 -5
- data/app/services/katello/smart_proxy_helper.rb +1 -6
- data/app/views/foreman/job_templates/upload_profile.erb +5 -0
- data/app/views/katello/api/v2/activation_keys/base.json.rabl +1 -1
- data/app/views/katello/api/v2/content_views/base.json.rabl +1 -0
- data/app/views/katello/api/v2/debs/thindex.json.rabl +6 -0
- data/app/views/katello/api/v2/docker_tags/_base.json.rabl +32 -0
- data/app/views/katello/api/v2/docker_tags/show.json.rabl +0 -5
- data/app/views/katello/api/v2/flatpak_remotes/index.json.rabl +6 -0
- data/app/views/katello/api/v2/host_debs/installed_debs.json.rabl +6 -0
- data/app/views/katello/api/v2/hosts_bulk_actions/applicable_errata.json.rabl +1 -1
- data/app/views/katello/api/v2/hosts_bulk_actions/applicable_erratum.json.rabl +9 -0
- data/app/views/katello/api/v2/hosts_bulk_actions/installable_errata.json.rabl +1 -1
- data/app/views/katello/api/v2/hosts_bulk_actions/{erratum.json.rabl → installable_erratum.json.rabl} +3 -3
- data/app/views/katello/api/v2/subscription_facet/base.json.rabl +1 -1
- data/config/initializers/monkeys.rb +1 -0
- data/config/routes/api/v2.rb +2 -2
- data/config/routes/overrides.rb +2 -7
- data/config/routes.rb +2 -0
- data/db/migrate/20211019192121_create_cdn_configuration.katello.rb +1 -1
- data/db/migrate/20250912000000_add_pulp_prn_fields.rb +73 -0
- data/db/migrate/20250912000001_populate_pulp_prn_fields.rb +403 -0
- data/db/migrate/20251009142516_remove_auto_attach_from_activation_keys.rb +5 -0
- data/db/migrate/20251009142517_remove_autoheal_from_subscription_facets.rb +5 -0
- data/db/seeds.d/111-upgrade_tasks.rb +2 -0
- data/engines/bastion_katello/app/assets/javascripts/bastion_katello/i18n/locale/el.po +2 -2
- data/engines/bastion_katello/app/assets/javascripts/bastion_katello/i18n/locale/fr.po +6 -1
- data/engines/bastion_katello/app/assets/javascripts/bastion_katello/i18n/locale/ja.po +5 -2
- data/engines/bastion_katello/app/assets/javascripts/bastion_katello/i18n/locale/ko.po +5 -2
- data/engines/bastion_katello/app/assets/javascripts/bastion_katello/i18n/locale/zh_CN.po +5 -2
- data/engines/bastion_katello/app/assets/javascripts/bastion_katello/i18n/translations.js +4 -4
- data/lib/katello/permission_creator.rb +2 -2
- data/lib/katello/permissions/host_permissions.rb +0 -6
- data/lib/katello/plugin.rb +16 -8
- data/lib/katello/tasks/jenkins.rake +1 -1
- data/lib/katello/tasks/upgrades/4.19/enable_structured_apt_for_deb.rake +87 -0
- data/lib/katello/tasks/upgrades/4.19/populate_repository_version_prns.rake +32 -0
- data/lib/katello/version.rb +1 -1
- data/lib/monkeys/fix_rpm_repository_gpgcheck.rb +38 -0
- data/locale/bn/LC_MESSAGES/katello.mo +0 -0
- data/locale/bn/katello.po +52 -349
- data/locale/bn_IN/LC_MESSAGES/katello.mo +0 -0
- data/locale/bn_IN/katello.po +52 -349
- data/locale/ca/LC_MESSAGES/katello.mo +0 -0
- data/locale/ca/katello.po +52 -349
- data/locale/cs/LC_MESSAGES/katello.mo +0 -0
- data/locale/cs/katello.po +54 -350
- data/locale/cs_CZ/LC_MESSAGES/katello.mo +0 -0
- data/locale/cs_CZ/katello.po +54 -351
- data/locale/de/LC_MESSAGES/katello.mo +0 -0
- data/locale/de/katello.po +56 -353
- data/locale/de_AT/LC_MESSAGES/katello.mo +0 -0
- data/locale/de_AT/katello.po +52 -349
- data/locale/de_DE/LC_MESSAGES/katello.mo +0 -0
- data/locale/de_DE/katello.po +52 -349
- data/locale/el/LC_MESSAGES/katello.mo +0 -0
- data/locale/el/katello.po +55 -352
- data/locale/en/LC_MESSAGES/katello.mo +0 -0
- data/locale/en/katello.po +54 -350
- data/locale/en_GB/LC_MESSAGES/katello.mo +0 -0
- data/locale/en_GB/katello.po +53 -350
- data/locale/en_US/LC_MESSAGES/katello.mo +0 -0
- data/locale/en_US/katello.po +52 -349
- data/locale/es/LC_MESSAGES/katello.mo +0 -0
- data/locale/es/katello.po +56 -353
- data/locale/et_EE/LC_MESSAGES/katello.mo +0 -0
- data/locale/et_EE/katello.po +52 -349
- data/locale/fr/LC_MESSAGES/katello.mo +0 -0
- data/locale/fr/katello.po +139 -435
- data/locale/gl/LC_MESSAGES/katello.mo +0 -0
- data/locale/gl/katello.po +52 -349
- data/locale/gu/LC_MESSAGES/katello.mo +0 -0
- data/locale/gu/katello.po +52 -349
- data/locale/he_IL/LC_MESSAGES/katello.mo +0 -0
- data/locale/he_IL/katello.po +52 -349
- data/locale/hi/LC_MESSAGES/katello.mo +0 -0
- data/locale/hi/katello.po +52 -349
- data/locale/id/LC_MESSAGES/katello.mo +0 -0
- data/locale/id/katello.po +52 -349
- data/locale/it/LC_MESSAGES/katello.mo +0 -0
- data/locale/it/katello.po +53 -350
- data/locale/ja/LC_MESSAGES/katello.mo +0 -0
- data/locale/ja/katello.po +143 -439
- data/locale/ka/LC_MESSAGES/katello.mo +0 -0
- data/locale/ka/katello.po +56 -353
- data/locale/katello.pot +695 -1152
- data/locale/kn/LC_MESSAGES/katello.mo +0 -0
- data/locale/kn/katello.po +52 -349
- data/locale/ko/LC_MESSAGES/katello.mo +0 -0
- data/locale/ko/katello.po +136 -432
- data/locale/ml_IN/LC_MESSAGES/katello.mo +0 -0
- data/locale/ml_IN/katello.po +52 -349
- data/locale/mr/LC_MESSAGES/katello.mo +0 -0
- data/locale/mr/katello.po +52 -349
- data/locale/nl_NL/LC_MESSAGES/katello.mo +0 -0
- data/locale/nl_NL/katello.po +52 -349
- data/locale/or/LC_MESSAGES/katello.mo +0 -0
- data/locale/or/katello.po +52 -349
- data/locale/pa/LC_MESSAGES/katello.mo +0 -0
- data/locale/pa/katello.po +52 -349
- data/locale/pl/LC_MESSAGES/katello.mo +0 -0
- data/locale/pl/katello.po +52 -349
- data/locale/pl_PL/LC_MESSAGES/katello.mo +0 -0
- data/locale/pl_PL/katello.po +52 -349
- data/locale/pt/LC_MESSAGES/katello.mo +0 -0
- data/locale/pt/katello.po +52 -349
- data/locale/pt_BR/LC_MESSAGES/katello.mo +0 -0
- data/locale/pt_BR/katello.po +56 -353
- data/locale/ro/LC_MESSAGES/katello.mo +0 -0
- data/locale/ro/katello.po +52 -349
- data/locale/ro_RO/LC_MESSAGES/katello.mo +0 -0
- data/locale/ro_RO/katello.po +52 -349
- data/locale/ru/LC_MESSAGES/katello.mo +0 -0
- data/locale/ru/katello.po +54 -351
- data/locale/sl/LC_MESSAGES/katello.mo +0 -0
- data/locale/sl/katello.po +52 -349
- data/locale/sv_SE/LC_MESSAGES/katello.mo +0 -0
- data/locale/sv_SE/katello.po +52 -349
- data/locale/ta/LC_MESSAGES/katello.mo +0 -0
- data/locale/ta/katello.po +52 -349
- data/locale/ta_IN/LC_MESSAGES/katello.mo +0 -0
- data/locale/ta_IN/katello.po +52 -349
- data/locale/te/LC_MESSAGES/katello.mo +0 -0
- data/locale/te/katello.po +52 -349
- data/locale/tr/LC_MESSAGES/katello.mo +0 -0
- data/locale/tr/katello.po +52 -349
- data/locale/vi/LC_MESSAGES/katello.mo +0 -0
- data/locale/vi/katello.po +52 -349
- data/locale/vi_VN/LC_MESSAGES/katello.mo +0 -0
- data/locale/vi_VN/katello.po +52 -349
- data/locale/zh/LC_MESSAGES/katello.mo +0 -0
- data/locale/zh/katello.po +52 -349
- data/locale/zh_CN/LC_MESSAGES/katello.mo +0 -0
- data/locale/zh_CN/katello.po +136 -432
- data/locale/zh_TW/LC_MESSAGES/katello.mo +0 -0
- data/locale/zh_TW/katello.po +54 -351
- data/webpack/components/Content/Details/__tests__/__snapshots__/ContentDetails.test.js.snap +2 -2
- data/webpack/components/extensions/HostDetails/Cards/SystemPurposeCard/SystemPurposeEditModal.js +0 -2
- data/webpack/components/extensions/HostDetails/Cards/SystemPurposeCard/__tests__/SystemPurposeEditModal.test.js +0 -2
- data/webpack/components/extensions/Hosts/ActionsBar/index.js +1 -0
- data/webpack/components/extensions/Hosts/BulkActions/BulkActionsConstants.js +7 -0
- data/webpack/components/extensions/Hosts/BulkActions/BulkChangeHostCollectionsModal/BulkChangeHostCollectionsModal.js +388 -0
- data/webpack/components/extensions/Hosts/BulkActions/BulkChangeHostCollectionsModal/__tests__/BulkChangeHostCollectionsModal.test.js +640 -0
- data/webpack/components/extensions/Hosts/BulkActions/BulkChangeHostCollectionsModal/actions.js +28 -0
- data/webpack/components/extensions/Hosts/BulkActions/BulkChangeHostCollectionsModal/index.js +71 -0
- data/webpack/components/extensions/Hosts/BulkActions/BulkErrataWizard/BulkErrataWizard.js +1 -1
- data/webpack/components/extensions/Hosts/BulkActions/BulkPackagesWizard/02_BulkPackagesTable.js +10 -3
- data/webpack/components/extensions/Hosts/BulkActions/BulkPackagesWizard/BulkPackagesWizard.js +51 -24
- data/webpack/components/extensions/Hosts/BulkActions/HostReview.js +7 -0
- data/webpack/containers/Application/config.js +11 -1
- data/webpack/global_index.js +3 -0
- data/webpack/scenes/{BootedContainerImages → ContainerImages/Booted}/BootedContainerImagesConstants.js +1 -1
- data/webpack/scenes/{BootedContainerImages → ContainerImages/Booted}/BootedContainerImagesPage.js +7 -43
- data/webpack/scenes/{BootedContainerImages → ContainerImages/Booted}/__tests__/bootedContainerImagesPage.test.js +1 -1
- data/webpack/scenes/ContainerImages/ContainerImagesPage.js +86 -0
- data/webpack/scenes/ContainerImages/LabelsAnnotationsModal.js +105 -0
- data/webpack/scenes/ContainerImages/Synced/Details/ManifestDetails.js +218 -0
- data/webpack/scenes/ContainerImages/Synced/Details/ManifestDetailsActions.js +15 -0
- data/webpack/scenes/ContainerImages/Synced/Details/ManifestDetailsSelectors.js +16 -0
- data/webpack/scenes/ContainerImages/Synced/Details/__tests__/ManifestDetails.test.js +395 -0
- data/webpack/scenes/ContainerImages/Synced/Details/__tests__/manifestDetails.fixtures.json +43 -0
- data/webpack/scenes/ContainerImages/Synced/Details/__tests__/manifestList.fixtures.json +58 -0
- data/webpack/scenes/ContainerImages/Synced/Details/index.js +4 -0
- data/webpack/scenes/ContainerImages/Synced/SyncedContainerImagesPage.js +359 -0
- data/webpack/scenes/ContainerImages/Synced/SyncedContainerImagesPage.scss +21 -0
- data/webpack/scenes/ContainerImages/Synced/__tests__/LabelsAnnotationsModal.test.js +69 -0
- data/webpack/scenes/ContainerImages/Synced/__tests__/SyncedContainerImagesPage.test.js +335 -0
- data/webpack/scenes/ContainerImages/Synced/__tests__/syncedContainerImages.fixtures.json +105 -0
- data/webpack/scenes/ContainerImages/TableEmptyState.js +67 -0
- data/webpack/scenes/ContainerImages/containerImagesHelpers.js +48 -0
- data/webpack/scenes/ContainerImages/index.js +4 -0
- data/webpack/scenes/ContentViews/Create/CreateContentViewForm.js +29 -3
- data/webpack/scenes/ContentViews/Create/__tests__/contentViewCreateResult.fixtures.json +1 -0
- data/webpack/scenes/ContentViews/Create/__tests__/createContentView.test.js +45 -1
- data/webpack/scenes/ContentViews/Delete/__tests__/affectedHosts.fixtures.json +0 -1
- data/webpack/scenes/ContentViews/Details/ContentViewInfo.js +59 -1
- data/webpack/scenes/ContentViews/Details/Filters/CVDebFilterContent.js +1 -0
- data/webpack/scenes/ContentViews/Details/Filters/Rules/DebPackage/AddEditDebPackageRuleModal.js +164 -24
- data/webpack/scenes/ContentViews/Details/Filters/__tests__/CVDebFilterContent.test.js +268 -0
- data/webpack/scenes/ContentViews/Details/Filters/__tests__/cvDebFilterDetail.fixtures.json +95 -0
- data/webpack/scenes/ContentViews/Details/Filters/__tests__/cvDebFilterRules.fixtures.json +31 -0
- data/webpack/scenes/ContentViews/Details/Filters/__tests__/emptyCVDebFilterRules.fixtures.json +10 -0
- data/webpack/scenes/ContentViews/Details/Versions/BulkDelete/__tests__/hosts.fixtures.json +0 -1
- data/webpack/scenes/ContentViews/Details/Versions/Delete/__tests__/cvAffectedHosts.fixture.json +0 -1
- data/webpack/scenes/ContentViews/Details/__tests__/contentViewRollingDetail.test.js +15 -0
- data/webpack/scenes/ContentViews/Details/__tests__/contentViewRollingDetails.fixtures.json +1 -0
- data/webpack/scenes/ContentViews/__tests__/contentViewPage.test.js +9 -0
- data/webpack/scenes/FlatpakRemotes/CreateEdit/CreateFlatpakRemoteModal.js +5 -3
- data/webpack/scenes/FlatpakRemotes/CreateEdit/EditFlatpakRemotesModal.js +1 -1
- data/webpack/scenes/FlatpakRemotes/CreateEdit/FlatpakRemoteform.js +35 -3
- data/webpack/scenes/FlatpakRemotes/Details/FlatpakRemoteDetails.js +1 -1
- data/webpack/scenes/FlatpakRemotes/Details/RemoteRepositories/RemoteRepositoriesTable.css +3 -0
- data/webpack/scenes/FlatpakRemotes/Details/RemoteRepositories/RemoteRepositoriesTable.js +63 -132
- data/webpack/scenes/FlatpakRemotes/FlatpakRemotesPage.js +67 -143
- data/webpack/scenes/SmartProxy/ExpandableCvDetails.js +10 -2
- data/webpack/scenes/SmartProxy/SmartProxyContentActions.js +13 -2
- data/webpack/scenes/SmartProxy/SmartProxyContentConstants.js +1 -0
- data/webpack/scenes/SmartProxy/SmartProxyExpandableTable.js +8 -2
- data/webpack/scenes/SmartProxy/__tests__/SmartProxyContentTest.js +67 -1
- data/webpack/scenes/Subscriptions/Details/__tests__/__snapshots__/SubscriptionDetails.test.js.snap +2 -2
- data/webpack/scenes/Subscriptions/SubscriptionConstants.js +0 -2
- data/webpack/scenes/Subscriptions/__tests__/__snapshots__/SubscriptionsActions.test.js.snap +2 -2
- metadata +83 -55
- data/app/lib/actions/katello/host/attach_subscriptions.rb +0 -59
- data/app/lib/actions/katello/host/auto_attach_subscriptions.rb +0 -22
- data/app/lib/actions/katello/host/remove_subscriptions.rb +0 -50
- data/app/lib/actions/katello/organization/simple_content_access/disable.rb +0 -25
- data/app/lib/actions/katello/organization/simple_content_access/enable.rb +0 -25
- data/app/lib/actions/katello/organization/simple_content_access/toggle.rb +0 -42
- data/lib/katello/tasks/migrate_structure_content_for_deb.rake +0 -105
- data/lib/katello/tasks/upgrades/4.2/remove_checksum_values.rake +0 -17
- data/locale/action_names.rb +0 -186
- /data/webpack/scenes/{BootedContainerImages → ContainerImages/Booted}/__tests__/bootedContainerImages.fixtures.js +0 -0
- /data/webpack/scenes/{BootedContainerImages → ContainerImages/Booted}/index.js +0 -0
|
@@ -0,0 +1,640 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { renderWithRedux, patientlyWaitFor, act } from 'react-testing-lib-wrapper';
|
|
3
|
+
import userEvent from '@testing-library/user-event';
|
|
4
|
+
import { addToast } from 'foremanReact/components/ToastsList';
|
|
5
|
+
import { nockInstance, assertNockRequest } from '../../../../../../test-utils/nockWrapper';
|
|
6
|
+
import katelloApi from '../../../../../../services/api';
|
|
7
|
+
import BulkChangeHostCollectionsModal from '../BulkChangeHostCollectionsModal';
|
|
8
|
+
|
|
9
|
+
jest.mock('foremanReact/components/ToastsList', () => ({
|
|
10
|
+
addToast: jest.fn(() => ({ type: 'ADD_TOAST' })),
|
|
11
|
+
}));
|
|
12
|
+
|
|
13
|
+
jest.mock('foremanReact/Root/Context/ForemanContext', () => ({
|
|
14
|
+
useForemanOrganization: () => ({ id: 1, name: 'Test Org' }),
|
|
15
|
+
}));
|
|
16
|
+
|
|
17
|
+
const hostCollectionsApiUrl = katelloApi.getApiUrl('/host_collections');
|
|
18
|
+
const autocompleteUrl = katelloApi.getApiUrl('/host_collections/auto_complete_search');
|
|
19
|
+
|
|
20
|
+
const mockHostCollections = {
|
|
21
|
+
total: 3,
|
|
22
|
+
subtotal: 3,
|
|
23
|
+
page: 1,
|
|
24
|
+
per_page: 5,
|
|
25
|
+
results: [
|
|
26
|
+
{
|
|
27
|
+
id: 1,
|
|
28
|
+
name: 'Test Host Collection 1',
|
|
29
|
+
description: 'First test collection',
|
|
30
|
+
max_hosts: 10,
|
|
31
|
+
unlimited_hosts: false,
|
|
32
|
+
total_hosts: 5,
|
|
33
|
+
},
|
|
34
|
+
{
|
|
35
|
+
id: 2,
|
|
36
|
+
name: 'Test Host Collection 2',
|
|
37
|
+
description: 'Second test collection',
|
|
38
|
+
max_hosts: null,
|
|
39
|
+
unlimited_hosts: true,
|
|
40
|
+
total_hosts: 3,
|
|
41
|
+
},
|
|
42
|
+
{
|
|
43
|
+
id: 3,
|
|
44
|
+
name: 'Test Host Collection 3',
|
|
45
|
+
description: '',
|
|
46
|
+
max_hosts: 20,
|
|
47
|
+
unlimited_hosts: false,
|
|
48
|
+
total_hosts: 0,
|
|
49
|
+
},
|
|
50
|
+
],
|
|
51
|
+
};
|
|
52
|
+
|
|
53
|
+
const renderOptions = (state = {}) => ({
|
|
54
|
+
apiNamespace: 'BULK_HOST_COLLECTIONS',
|
|
55
|
+
initialState: {
|
|
56
|
+
API: {
|
|
57
|
+
...state,
|
|
58
|
+
},
|
|
59
|
+
},
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
const defaultProps = {
|
|
63
|
+
isOpen: true,
|
|
64
|
+
closeModal: jest.fn(),
|
|
65
|
+
fetchBulkParams: jest.fn(() => 'name ~ test'),
|
|
66
|
+
selectedCount: 5,
|
|
67
|
+
};
|
|
68
|
+
|
|
69
|
+
beforeEach(() => {
|
|
70
|
+
jest.clearAllMocks();
|
|
71
|
+
});
|
|
72
|
+
|
|
73
|
+
test('renders modal when open', async () => {
|
|
74
|
+
const autocompleteScope = nockInstance
|
|
75
|
+
.get(autocompleteUrl)
|
|
76
|
+
.query(true)
|
|
77
|
+
.reply(200, [])
|
|
78
|
+
.persist();
|
|
79
|
+
|
|
80
|
+
const hostCollectionsScope = nockInstance
|
|
81
|
+
.get(hostCollectionsApiUrl)
|
|
82
|
+
.query(true)
|
|
83
|
+
.reply(200, mockHostCollections)
|
|
84
|
+
.persist();
|
|
85
|
+
|
|
86
|
+
const { getByText } = renderWithRedux(
|
|
87
|
+
<BulkChangeHostCollectionsModal {...defaultProps} />,
|
|
88
|
+
renderOptions(),
|
|
89
|
+
);
|
|
90
|
+
|
|
91
|
+
await patientlyWaitFor(() => {
|
|
92
|
+
expect(getByText('Change host collections')).toBeInTheDocument();
|
|
93
|
+
expect(getByText('Add to host collections')).toBeInTheDocument();
|
|
94
|
+
expect(getByText('Remove from host collections')).toBeInTheDocument();
|
|
95
|
+
});
|
|
96
|
+
|
|
97
|
+
assertNockRequest(hostCollectionsScope, false);
|
|
98
|
+
assertNockRequest(autocompleteScope, false);
|
|
99
|
+
});
|
|
100
|
+
|
|
101
|
+
test('displays host collections table', async () => {
|
|
102
|
+
const autocompleteScope = nockInstance
|
|
103
|
+
.get(autocompleteUrl)
|
|
104
|
+
.query(true)
|
|
105
|
+
.reply(200, [])
|
|
106
|
+
.persist();
|
|
107
|
+
|
|
108
|
+
const hostCollectionsScope = nockInstance
|
|
109
|
+
.get(hostCollectionsApiUrl)
|
|
110
|
+
.query(true)
|
|
111
|
+
.reply(200, mockHostCollections)
|
|
112
|
+
.persist();
|
|
113
|
+
|
|
114
|
+
const { getByText } = renderWithRedux(
|
|
115
|
+
<BulkChangeHostCollectionsModal {...defaultProps} />,
|
|
116
|
+
renderOptions(),
|
|
117
|
+
);
|
|
118
|
+
|
|
119
|
+
await patientlyWaitFor(() => {
|
|
120
|
+
expect(getByText('Test Host Collection 1')).toBeInTheDocument();
|
|
121
|
+
expect(getByText('Test Host Collection 2')).toBeInTheDocument();
|
|
122
|
+
expect(getByText('Test Host Collection 3')).toBeInTheDocument();
|
|
123
|
+
expect(getByText('First test collection')).toBeInTheDocument();
|
|
124
|
+
expect(getByText('Second test collection')).toBeInTheDocument();
|
|
125
|
+
expect(getByText('5/10')).toBeInTheDocument(); // limit display
|
|
126
|
+
expect(getByText('3/unlimited')).toBeInTheDocument(); // unlimited hosts
|
|
127
|
+
});
|
|
128
|
+
|
|
129
|
+
assertNockRequest(hostCollectionsScope, false);
|
|
130
|
+
assertNockRequest(autocompleteScope, false);
|
|
131
|
+
});
|
|
132
|
+
|
|
133
|
+
test('Save button is disabled when no host collections selected', async () => {
|
|
134
|
+
const autocompleteScope = nockInstance
|
|
135
|
+
.get(autocompleteUrl)
|
|
136
|
+
.query(true)
|
|
137
|
+
.reply(200, [])
|
|
138
|
+
.persist();
|
|
139
|
+
|
|
140
|
+
const hostCollectionsScope = nockInstance
|
|
141
|
+
.get(hostCollectionsApiUrl)
|
|
142
|
+
.query(true)
|
|
143
|
+
.reply(200, mockHostCollections)
|
|
144
|
+
.persist();
|
|
145
|
+
|
|
146
|
+
const { getAllByRole } = renderWithRedux(
|
|
147
|
+
<BulkChangeHostCollectionsModal {...defaultProps} />,
|
|
148
|
+
renderOptions(),
|
|
149
|
+
);
|
|
150
|
+
|
|
151
|
+
await patientlyWaitFor(() => {
|
|
152
|
+
const saveButton = getAllByRole('button', { name: 'Save' })[0];
|
|
153
|
+
expect(saveButton).toBeInTheDocument();
|
|
154
|
+
expect(saveButton).toHaveAttribute('aria-disabled', 'true');
|
|
155
|
+
});
|
|
156
|
+
|
|
157
|
+
assertNockRequest(hostCollectionsScope, false);
|
|
158
|
+
assertNockRequest(autocompleteScope, false);
|
|
159
|
+
});
|
|
160
|
+
|
|
161
|
+
test('Save button is enabled when host collection is selected', async () => {
|
|
162
|
+
const autocompleteScope = nockInstance
|
|
163
|
+
.get(autocompleteUrl)
|
|
164
|
+
.query(true)
|
|
165
|
+
.reply(200, [])
|
|
166
|
+
.persist();
|
|
167
|
+
|
|
168
|
+
const hostCollectionsScope = nockInstance
|
|
169
|
+
.get(hostCollectionsApiUrl)
|
|
170
|
+
.query(true)
|
|
171
|
+
.reply(200, mockHostCollections)
|
|
172
|
+
.persist();
|
|
173
|
+
|
|
174
|
+
const { getAllByRole, getByText } = renderWithRedux(
|
|
175
|
+
<BulkChangeHostCollectionsModal {...defaultProps} />,
|
|
176
|
+
renderOptions(),
|
|
177
|
+
);
|
|
178
|
+
|
|
179
|
+
await patientlyWaitFor(() => {
|
|
180
|
+
expect(getByText('Test Host Collection 1')).toBeInTheDocument();
|
|
181
|
+
});
|
|
182
|
+
|
|
183
|
+
let checkboxes;
|
|
184
|
+
await act(async () => {
|
|
185
|
+
checkboxes = getAllByRole('checkbox');
|
|
186
|
+
// Click first host collection checkbox (skip the select all checkbox)
|
|
187
|
+
await userEvent.click(checkboxes[1]);
|
|
188
|
+
});
|
|
189
|
+
|
|
190
|
+
await patientlyWaitFor(() => {
|
|
191
|
+
const saveButton = getAllByRole('button', { name: 'Save' })[0];
|
|
192
|
+
expect(saveButton).toHaveAttribute('aria-disabled', 'false');
|
|
193
|
+
});
|
|
194
|
+
|
|
195
|
+
assertNockRequest(hostCollectionsScope, false);
|
|
196
|
+
assertNockRequest(autocompleteScope, false);
|
|
197
|
+
});
|
|
198
|
+
|
|
199
|
+
// Test loading state of Save button
|
|
200
|
+
test('Save button is disabled and shows loading indicator while fetching host collections', async () => {
|
|
201
|
+
const autocompleteScope = nockInstance
|
|
202
|
+
.get(autocompleteUrl)
|
|
203
|
+
.query(true)
|
|
204
|
+
.reply(200, [])
|
|
205
|
+
.persist();
|
|
206
|
+
|
|
207
|
+
const hostCollectionsScope = nockInstance
|
|
208
|
+
.get(hostCollectionsApiUrl)
|
|
209
|
+
.query(true)
|
|
210
|
+
.reply(200, mockHostCollections)
|
|
211
|
+
.persist();
|
|
212
|
+
|
|
213
|
+
const { getAllByRole } = renderWithRedux(
|
|
214
|
+
<BulkChangeHostCollectionsModal {...defaultProps} />,
|
|
215
|
+
renderOptions(),
|
|
216
|
+
);
|
|
217
|
+
|
|
218
|
+
// Immediately after render, before host collections resolve
|
|
219
|
+
const saveButton = getAllByRole('button', { name: /Save/ })[0];
|
|
220
|
+
expect(saveButton).toBeInTheDocument();
|
|
221
|
+
expect(saveButton).toHaveAttribute('aria-disabled', 'true');
|
|
222
|
+
|
|
223
|
+
// Check for loading indicator (adjust selector as needed for your implementation)
|
|
224
|
+
// Example: spinner, loading text, etc.
|
|
225
|
+
// If your Save button shows a spinner or "Loading..." text, check for it:
|
|
226
|
+
// expect(getByText(/loading/i)).toBeInTheDocument();
|
|
227
|
+
// Or if you use a spinner with a test id:
|
|
228
|
+
// expect(saveButton.querySelector('[data-testid="loading-spinner"]')).toBeInTheDocument();
|
|
229
|
+
|
|
230
|
+
// Wait for host collections to load
|
|
231
|
+
await patientlyWaitFor(() => {
|
|
232
|
+
expect(saveButton).toBeInTheDocument();
|
|
233
|
+
// After loading, Save button should still be disabled if no selection
|
|
234
|
+
expect(saveButton).toHaveAttribute('aria-disabled', 'true');
|
|
235
|
+
});
|
|
236
|
+
|
|
237
|
+
assertNockRequest(hostCollectionsScope, false);
|
|
238
|
+
assertNockRequest(autocompleteScope, false);
|
|
239
|
+
});
|
|
240
|
+
|
|
241
|
+
test('switches between Add and Remove radio buttons', async () => {
|
|
242
|
+
const autocompleteScope = nockInstance
|
|
243
|
+
.get(autocompleteUrl)
|
|
244
|
+
.query(true)
|
|
245
|
+
.reply(200, [])
|
|
246
|
+
.persist();
|
|
247
|
+
|
|
248
|
+
const hostCollectionsScope = nockInstance
|
|
249
|
+
.get(hostCollectionsApiUrl)
|
|
250
|
+
.query(true)
|
|
251
|
+
.reply(200, mockHostCollections)
|
|
252
|
+
.persist();
|
|
253
|
+
|
|
254
|
+
const { getByLabelText } = renderWithRedux(
|
|
255
|
+
<BulkChangeHostCollectionsModal {...defaultProps} />,
|
|
256
|
+
renderOptions(),
|
|
257
|
+
);
|
|
258
|
+
|
|
259
|
+
await patientlyWaitFor(() => {
|
|
260
|
+
const addRadio = getByLabelText('Add to host collections');
|
|
261
|
+
const removeRadio = getByLabelText('Remove from host collections');
|
|
262
|
+
|
|
263
|
+
expect(addRadio).toBeChecked();
|
|
264
|
+
expect(removeRadio).not.toBeChecked();
|
|
265
|
+
});
|
|
266
|
+
|
|
267
|
+
await act(async () => {
|
|
268
|
+
const removeRadio = getByLabelText('Remove from host collections');
|
|
269
|
+
userEvent.click(removeRadio);
|
|
270
|
+
});
|
|
271
|
+
|
|
272
|
+
await patientlyWaitFor(() => {
|
|
273
|
+
const addRadio = getByLabelText('Add to host collections');
|
|
274
|
+
const removeRadio = getByLabelText('Remove from host collections');
|
|
275
|
+
|
|
276
|
+
expect(addRadio).not.toBeChecked();
|
|
277
|
+
expect(removeRadio).toBeChecked();
|
|
278
|
+
});
|
|
279
|
+
|
|
280
|
+
assertNockRequest(hostCollectionsScope, false);
|
|
281
|
+
assertNockRequest(autocompleteScope, false);
|
|
282
|
+
});
|
|
283
|
+
|
|
284
|
+
test('closes modal and clears selections on Cancel', async () => {
|
|
285
|
+
const autocompleteScope = nockInstance
|
|
286
|
+
.get(autocompleteUrl)
|
|
287
|
+
.query(true)
|
|
288
|
+
.reply(200, [])
|
|
289
|
+
.persist();
|
|
290
|
+
|
|
291
|
+
const hostCollectionsScope = nockInstance
|
|
292
|
+
.get(hostCollectionsApiUrl)
|
|
293
|
+
.query(true)
|
|
294
|
+
.reply(200, mockHostCollections)
|
|
295
|
+
.persist();
|
|
296
|
+
|
|
297
|
+
const closeModal = jest.fn();
|
|
298
|
+
|
|
299
|
+
const { getAllByRole } = renderWithRedux(
|
|
300
|
+
<BulkChangeHostCollectionsModal
|
|
301
|
+
{...defaultProps}
|
|
302
|
+
closeModal={closeModal}
|
|
303
|
+
/>,
|
|
304
|
+
renderOptions(),
|
|
305
|
+
);
|
|
306
|
+
|
|
307
|
+
await patientlyWaitFor(() => {
|
|
308
|
+
const cancelButton = getAllByRole('button', { name: 'Cancel' })[0];
|
|
309
|
+
expect(cancelButton).toBeInTheDocument();
|
|
310
|
+
});
|
|
311
|
+
|
|
312
|
+
await act(async () => {
|
|
313
|
+
const cancelButton = getAllByRole('button', { name: 'Cancel' })[0];
|
|
314
|
+
userEvent.click(cancelButton);
|
|
315
|
+
});
|
|
316
|
+
|
|
317
|
+
expect(closeModal).toHaveBeenCalled();
|
|
318
|
+
assertNockRequest(hostCollectionsScope, false);
|
|
319
|
+
assertNockRequest(autocompleteScope, false);
|
|
320
|
+
});
|
|
321
|
+
|
|
322
|
+
test('does not fetch data when modal is closed', () => {
|
|
323
|
+
const { queryByText } = renderWithRedux(
|
|
324
|
+
<BulkChangeHostCollectionsModal
|
|
325
|
+
{...defaultProps}
|
|
326
|
+
isOpen={false}
|
|
327
|
+
/>,
|
|
328
|
+
renderOptions(),
|
|
329
|
+
);
|
|
330
|
+
|
|
331
|
+
expect(queryByText('Change host collections')).not.toBeInTheDocument();
|
|
332
|
+
});
|
|
333
|
+
|
|
334
|
+
test('shows success toast notification on successful save', async () => {
|
|
335
|
+
const autocompleteScope = nockInstance
|
|
336
|
+
.get(autocompleteUrl)
|
|
337
|
+
.query(true)
|
|
338
|
+
.reply(200, [])
|
|
339
|
+
.persist();
|
|
340
|
+
|
|
341
|
+
const hostCollectionsScope = nockInstance
|
|
342
|
+
.get(hostCollectionsApiUrl)
|
|
343
|
+
.query(true)
|
|
344
|
+
.reply(200, mockHostCollections)
|
|
345
|
+
.persist();
|
|
346
|
+
|
|
347
|
+
const saveScope = nockInstance
|
|
348
|
+
.put('/api/v2/hosts/bulk/add_host_collections')
|
|
349
|
+
.reply(200, { displayMessages: ['Host collections updated'] });
|
|
350
|
+
|
|
351
|
+
const hostsRefreshScope = nockInstance
|
|
352
|
+
.get('/api/hosts')
|
|
353
|
+
.query(true)
|
|
354
|
+
.reply(200, { results: [] });
|
|
355
|
+
|
|
356
|
+
const { getAllByRole, getByText } = renderWithRedux(
|
|
357
|
+
<BulkChangeHostCollectionsModal {...defaultProps} />,
|
|
358
|
+
renderOptions(),
|
|
359
|
+
);
|
|
360
|
+
|
|
361
|
+
await patientlyWaitFor(() => {
|
|
362
|
+
expect(getByText('Test Host Collection 1')).toBeInTheDocument();
|
|
363
|
+
});
|
|
364
|
+
|
|
365
|
+
// Simulate selecting a host collection
|
|
366
|
+
let checkboxes;
|
|
367
|
+
await act(async () => {
|
|
368
|
+
checkboxes = getAllByRole('checkbox');
|
|
369
|
+
// Click first host collection checkbox (skip the select all checkbox)
|
|
370
|
+
await userEvent.click(checkboxes[1]);
|
|
371
|
+
});
|
|
372
|
+
|
|
373
|
+
// Save button should be enabled now
|
|
374
|
+
await patientlyWaitFor(() => {
|
|
375
|
+
const saveButton = getAllByRole('button', { name: 'Save' })[0];
|
|
376
|
+
expect(saveButton).toHaveAttribute('aria-disabled', 'false');
|
|
377
|
+
});
|
|
378
|
+
|
|
379
|
+
// Click Save
|
|
380
|
+
await act(async () => {
|
|
381
|
+
const saveButton = getAllByRole('button', { name: 'Save' })[0];
|
|
382
|
+
await userEvent.click(saveButton);
|
|
383
|
+
});
|
|
384
|
+
|
|
385
|
+
await patientlyWaitFor(() => {
|
|
386
|
+
expect(addToast).toHaveBeenCalledWith(expect.objectContaining({ type: 'success' }));
|
|
387
|
+
});
|
|
388
|
+
|
|
389
|
+
assertNockRequest(saveScope, false);
|
|
390
|
+
assertNockRequest(hostsRefreshScope, false);
|
|
391
|
+
assertNockRequest(hostCollectionsScope, false);
|
|
392
|
+
assertNockRequest(autocompleteScope, false);
|
|
393
|
+
});
|
|
394
|
+
|
|
395
|
+
// Test for error toast notification
|
|
396
|
+
test('shows error toast notification on failed save', async () => {
|
|
397
|
+
const autocompleteScope = nockInstance
|
|
398
|
+
.get(autocompleteUrl)
|
|
399
|
+
.query(true)
|
|
400
|
+
.reply(200, [])
|
|
401
|
+
.persist();
|
|
402
|
+
|
|
403
|
+
const hostCollectionsScope = nockInstance
|
|
404
|
+
.get(hostCollectionsApiUrl)
|
|
405
|
+
.query(true)
|
|
406
|
+
.reply(200, mockHostCollections)
|
|
407
|
+
.persist();
|
|
408
|
+
|
|
409
|
+
const saveScope = nockInstance
|
|
410
|
+
.put('/api/v2/hosts/bulk/add_host_collections')
|
|
411
|
+
.reply(500, { error: { message: 'Internal Server Error' } });
|
|
412
|
+
|
|
413
|
+
const { getAllByRole, getByText } = renderWithRedux(
|
|
414
|
+
<BulkChangeHostCollectionsModal {...defaultProps} />,
|
|
415
|
+
renderOptions(),
|
|
416
|
+
);
|
|
417
|
+
|
|
418
|
+
await patientlyWaitFor(() => {
|
|
419
|
+
expect(getByText('Test Host Collection 1')).toBeInTheDocument();
|
|
420
|
+
});
|
|
421
|
+
|
|
422
|
+
// Simulate selecting a host collection
|
|
423
|
+
let checkboxes;
|
|
424
|
+
await act(async () => {
|
|
425
|
+
checkboxes = getAllByRole('checkbox');
|
|
426
|
+
// Click first host collection checkbox (skip the select all checkbox)
|
|
427
|
+
await userEvent.click(checkboxes[1]);
|
|
428
|
+
});
|
|
429
|
+
|
|
430
|
+
// Save button should be enabled now
|
|
431
|
+
await patientlyWaitFor(() => {
|
|
432
|
+
const saveButton = getAllByRole('button', { name: 'Save' })[0];
|
|
433
|
+
expect(saveButton).toHaveAttribute('aria-disabled', 'false');
|
|
434
|
+
});
|
|
435
|
+
|
|
436
|
+
// Click Save
|
|
437
|
+
await act(async () => {
|
|
438
|
+
const saveButton = getAllByRole('button', { name: 'Save' })[0];
|
|
439
|
+
await userEvent.click(saveButton);
|
|
440
|
+
});
|
|
441
|
+
|
|
442
|
+
await patientlyWaitFor(() => {
|
|
443
|
+
expect(addToast).toHaveBeenCalledWith(expect.objectContaining({ type: 'danger' }));
|
|
444
|
+
});
|
|
445
|
+
|
|
446
|
+
assertNockRequest(saveScope, false);
|
|
447
|
+
assertNockRequest(hostCollectionsScope, false);
|
|
448
|
+
assertNockRequest(autocompleteScope, false);
|
|
449
|
+
});
|
|
450
|
+
|
|
451
|
+
// Test for Add action API call
|
|
452
|
+
test('makes correct API call when Add action is selected', async () => {
|
|
453
|
+
const autocompleteScope = nockInstance
|
|
454
|
+
.get(autocompleteUrl)
|
|
455
|
+
.query(true)
|
|
456
|
+
.reply(200, [])
|
|
457
|
+
.persist();
|
|
458
|
+
|
|
459
|
+
const hostCollectionsScope = nockInstance
|
|
460
|
+
.get(hostCollectionsApiUrl)
|
|
461
|
+
.query(true)
|
|
462
|
+
.reply(200, mockHostCollections)
|
|
463
|
+
.persist();
|
|
464
|
+
|
|
465
|
+
const saveScope = nockInstance
|
|
466
|
+
.put('/api/v2/hosts/bulk/add_host_collections')
|
|
467
|
+
.reply(200, { displayMessages: ['Host collections updated'] });
|
|
468
|
+
|
|
469
|
+
const hostsRefreshScope = nockInstance
|
|
470
|
+
.get('/api/hosts')
|
|
471
|
+
.query(true)
|
|
472
|
+
.reply(200, { results: [] });
|
|
473
|
+
|
|
474
|
+
const { getAllByRole, getByText, getByLabelText } = renderWithRedux(
|
|
475
|
+
<BulkChangeHostCollectionsModal {...defaultProps} />,
|
|
476
|
+
renderOptions(),
|
|
477
|
+
);
|
|
478
|
+
|
|
479
|
+
await patientlyWaitFor(() => {
|
|
480
|
+
expect(getByText('Test Host Collection 1')).toBeInTheDocument();
|
|
481
|
+
});
|
|
482
|
+
|
|
483
|
+
// Ensure Add radio is selected (default)
|
|
484
|
+
const addRadio = getByLabelText('Add to host collections');
|
|
485
|
+
expect(addRadio).toBeChecked();
|
|
486
|
+
|
|
487
|
+
// Select a host collection
|
|
488
|
+
let checkboxes;
|
|
489
|
+
await act(async () => {
|
|
490
|
+
checkboxes = getAllByRole('checkbox');
|
|
491
|
+
await userEvent.click(checkboxes[1]);
|
|
492
|
+
});
|
|
493
|
+
|
|
494
|
+
// Click Save
|
|
495
|
+
await act(async () => {
|
|
496
|
+
const saveButton = getAllByRole('button', { name: 'Save' })[0];
|
|
497
|
+
await userEvent.click(saveButton);
|
|
498
|
+
});
|
|
499
|
+
|
|
500
|
+
// Verify the API call was made and wait for all async operations
|
|
501
|
+
await act(async () => {
|
|
502
|
+
await patientlyWaitFor(() => {
|
|
503
|
+
assertNockRequest(saveScope);
|
|
504
|
+
expect(addToast).toHaveBeenCalled();
|
|
505
|
+
});
|
|
506
|
+
});
|
|
507
|
+
|
|
508
|
+
assertNockRequest(hostCollectionsScope, false);
|
|
509
|
+
assertNockRequest(autocompleteScope, false);
|
|
510
|
+
assertNockRequest(hostsRefreshScope, false);
|
|
511
|
+
});
|
|
512
|
+
|
|
513
|
+
// Test for Remove action API call
|
|
514
|
+
test('makes correct API call when Remove action is selected', async () => {
|
|
515
|
+
const autocompleteScope = nockInstance
|
|
516
|
+
.get(autocompleteUrl)
|
|
517
|
+
.query(true)
|
|
518
|
+
.reply(200, [])
|
|
519
|
+
.persist();
|
|
520
|
+
|
|
521
|
+
const hostCollectionsScope = nockInstance
|
|
522
|
+
.get(hostCollectionsApiUrl)
|
|
523
|
+
.query(true)
|
|
524
|
+
.reply(200, mockHostCollections)
|
|
525
|
+
.persist();
|
|
526
|
+
|
|
527
|
+
const saveScope = nockInstance
|
|
528
|
+
.put('/api/v2/hosts/bulk/remove_host_collections')
|
|
529
|
+
.reply(200, { displayMessages: ['Host collections updated'] });
|
|
530
|
+
|
|
531
|
+
const hostsRefreshScope = nockInstance
|
|
532
|
+
.get('/api/hosts')
|
|
533
|
+
.query(true)
|
|
534
|
+
.reply(200, { results: [] });
|
|
535
|
+
|
|
536
|
+
const { getAllByRole, getByText, getByLabelText } = renderWithRedux(
|
|
537
|
+
<BulkChangeHostCollectionsModal {...defaultProps} />,
|
|
538
|
+
renderOptions(),
|
|
539
|
+
);
|
|
540
|
+
|
|
541
|
+
await patientlyWaitFor(() => {
|
|
542
|
+
expect(getByText('Test Host Collection 2')).toBeInTheDocument();
|
|
543
|
+
});
|
|
544
|
+
|
|
545
|
+
// Select Remove radio button
|
|
546
|
+
await act(async () => {
|
|
547
|
+
const removeRadio = getByLabelText('Remove from host collections');
|
|
548
|
+
await userEvent.click(removeRadio);
|
|
549
|
+
});
|
|
550
|
+
|
|
551
|
+
await patientlyWaitFor(() => {
|
|
552
|
+
const removeRadio = getByLabelText('Remove from host collections');
|
|
553
|
+
expect(removeRadio).toBeChecked();
|
|
554
|
+
});
|
|
555
|
+
|
|
556
|
+
// Select a different host collection (2nd one)
|
|
557
|
+
let checkboxes;
|
|
558
|
+
await act(async () => {
|
|
559
|
+
checkboxes = getAllByRole('checkbox');
|
|
560
|
+
await userEvent.click(checkboxes[2]); // Select 2nd host collection
|
|
561
|
+
});
|
|
562
|
+
|
|
563
|
+
// Click Save
|
|
564
|
+
await act(async () => {
|
|
565
|
+
const saveButton = getAllByRole('button', { name: 'Save' })[0];
|
|
566
|
+
await userEvent.click(saveButton);
|
|
567
|
+
});
|
|
568
|
+
|
|
569
|
+
// Verify the API call was made to remove endpoint and wait for all async operations
|
|
570
|
+
await act(async () => {
|
|
571
|
+
await patientlyWaitFor(() => {
|
|
572
|
+
assertNockRequest(saveScope);
|
|
573
|
+
expect(addToast).toHaveBeenCalled();
|
|
574
|
+
});
|
|
575
|
+
});
|
|
576
|
+
|
|
577
|
+
assertNockRequest(hostCollectionsScope, false);
|
|
578
|
+
assertNockRequest(autocompleteScope, false);
|
|
579
|
+
assertNockRequest(hostsRefreshScope, false);
|
|
580
|
+
});
|
|
581
|
+
|
|
582
|
+
// Test for multiple host collections selected
|
|
583
|
+
test('makes correct API call with multiple host collections', async () => {
|
|
584
|
+
const autocompleteScope = nockInstance
|
|
585
|
+
.get(autocompleteUrl)
|
|
586
|
+
.query(true)
|
|
587
|
+
.reply(200, [])
|
|
588
|
+
.persist();
|
|
589
|
+
|
|
590
|
+
const hostCollectionsScope = nockInstance
|
|
591
|
+
.get(hostCollectionsApiUrl)
|
|
592
|
+
.query(true)
|
|
593
|
+
.reply(200, mockHostCollections)
|
|
594
|
+
.persist();
|
|
595
|
+
|
|
596
|
+
const saveScope = nockInstance
|
|
597
|
+
.put('/api/v2/hosts/bulk/add_host_collections')
|
|
598
|
+
.reply(200, { displayMessages: ['Host collections updated'] });
|
|
599
|
+
|
|
600
|
+
const hostsRefreshScope = nockInstance
|
|
601
|
+
.get('/api/hosts')
|
|
602
|
+
.query(true)
|
|
603
|
+
.reply(200, { results: [] });
|
|
604
|
+
|
|
605
|
+
const { getAllByRole, getByText } = renderWithRedux(
|
|
606
|
+
<BulkChangeHostCollectionsModal {...defaultProps} />,
|
|
607
|
+
renderOptions(),
|
|
608
|
+
);
|
|
609
|
+
|
|
610
|
+
await patientlyWaitFor(() => {
|
|
611
|
+
expect(getByText('Test Host Collection 1')).toBeInTheDocument();
|
|
612
|
+
});
|
|
613
|
+
|
|
614
|
+
// Select all three host collections
|
|
615
|
+
let checkboxes;
|
|
616
|
+
await act(async () => {
|
|
617
|
+
checkboxes = getAllByRole('checkbox');
|
|
618
|
+
await userEvent.click(checkboxes[1]); // First HC
|
|
619
|
+
await userEvent.click(checkboxes[2]); // Second HC
|
|
620
|
+
await userEvent.click(checkboxes[3]); // Third HC
|
|
621
|
+
});
|
|
622
|
+
|
|
623
|
+
// Click Save
|
|
624
|
+
await act(async () => {
|
|
625
|
+
const saveButton = getAllByRole('button', { name: 'Save' })[0];
|
|
626
|
+
await userEvent.click(saveButton);
|
|
627
|
+
});
|
|
628
|
+
|
|
629
|
+
// Verify the API call includes all selected host collection IDs and wait for all async operations
|
|
630
|
+
await act(async () => {
|
|
631
|
+
await patientlyWaitFor(() => {
|
|
632
|
+
assertNockRequest(saveScope);
|
|
633
|
+
expect(addToast).toHaveBeenCalled();
|
|
634
|
+
});
|
|
635
|
+
});
|
|
636
|
+
|
|
637
|
+
assertNockRequest(hostCollectionsScope, false);
|
|
638
|
+
assertNockRequest(autocompleteScope, false);
|
|
639
|
+
assertNockRequest(hostsRefreshScope, false);
|
|
640
|
+
});
|
data/webpack/components/extensions/Hosts/BulkActions/BulkChangeHostCollectionsModal/actions.js
ADDED
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { API_OPERATIONS, put } from 'foremanReact/redux/API';
|
|
2
|
+
import { errorToast } from '../../../../../scenes/Tasks/helpers';
|
|
3
|
+
import { foremanApi } from '../../../../../services/api';
|
|
4
|
+
|
|
5
|
+
export const BULK_ADD_HOST_COLLECTIONS_KEY = 'BULK_ADD_HOST_COLLECTIONS';
|
|
6
|
+
export const BULK_REMOVE_HOST_COLLECTIONS_KEY = 'BULK_REMOVE_HOST_COLLECTIONS';
|
|
7
|
+
|
|
8
|
+
export const bulkAddHostCollections =
|
|
9
|
+
(params, handleSuccess, handleError) => put({
|
|
10
|
+
type: API_OPERATIONS.PUT,
|
|
11
|
+
key: BULK_ADD_HOST_COLLECTIONS_KEY,
|
|
12
|
+
url: foremanApi.getApiUrl('/hosts/bulk/add_host_collections'),
|
|
13
|
+
handleSuccess,
|
|
14
|
+
handleError,
|
|
15
|
+
errorToast,
|
|
16
|
+
params,
|
|
17
|
+
});
|
|
18
|
+
|
|
19
|
+
export const bulkRemoveHostCollections =
|
|
20
|
+
(params, handleSuccess, handleError) => put({
|
|
21
|
+
type: API_OPERATIONS.PUT,
|
|
22
|
+
key: BULK_REMOVE_HOST_COLLECTIONS_KEY,
|
|
23
|
+
url: foremanApi.getApiUrl('/hosts/bulk/remove_host_collections'),
|
|
24
|
+
handleSuccess,
|
|
25
|
+
handleError,
|
|
26
|
+
errorToast,
|
|
27
|
+
params,
|
|
28
|
+
});
|