katello 4.12.0.rc3 → 4.13.0.rc1
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of katello might be problematic. Click here for more details.
- checksums.yaml +4 -4
- data/README.md +0 -1
- data/app/assets/javascripts/katello/locale/bn/katello.js +3365 -3350
- data/app/assets/javascripts/katello/locale/bn_IN/katello.js +3136 -3121
- data/app/assets/javascripts/katello/locale/ca/katello.js +3588 -3576
- data/app/assets/javascripts/katello/locale/cs/katello.js +3499 -3487
- data/app/assets/javascripts/katello/locale/cs_CZ/katello.js +4186 -4186
- data/app/assets/javascripts/katello/locale/de/katello.js +5553 -5562
- data/app/assets/javascripts/katello/locale/de_AT/katello.js +3008 -2993
- data/app/assets/javascripts/katello/locale/de_DE/katello.js +3066 -3051
- data/app/assets/javascripts/katello/locale/el/katello.js +3376 -3370
- data/app/assets/javascripts/katello/locale/en/katello.js +3008 -2993
- data/app/assets/javascripts/katello/locale/en_GB/katello.js +3076 -3073
- data/app/assets/javascripts/katello/locale/en_US/katello.js +3008 -2993
- data/app/assets/javascripts/katello/locale/es/katello.js +5366 -5372
- data/app/assets/javascripts/katello/locale/et_EE/katello.js +3008 -2993
- data/app/assets/javascripts/katello/locale/fr/katello.js +5975 -5984
- data/app/assets/javascripts/katello/locale/gl/katello.js +3125 -3113
- data/app/assets/javascripts/katello/locale/gu/katello.js +3119 -3104
- data/app/assets/javascripts/katello/locale/he_IL/katello.js +3020 -3005
- data/app/assets/javascripts/katello/locale/hi/katello.js +3137 -3122
- data/app/assets/javascripts/katello/locale/id/katello.js +3008 -2993
- data/app/assets/javascripts/katello/locale/it/katello.js +4469 -4466
- data/app/assets/javascripts/katello/locale/ja/katello.js +5969 -5978
- data/app/assets/javascripts/katello/locale/ka/katello.js +5649 -5652
- data/app/assets/javascripts/katello/locale/kn/katello.js +3136 -3121
- data/app/assets/javascripts/katello/locale/ko/katello.js +4717 -4720
- data/app/assets/javascripts/katello/locale/locale/katello.js +1050 -1084
- data/app/assets/javascripts/katello/locale/ml_IN/katello.js +3008 -2993
- data/app/assets/javascripts/katello/locale/mr/katello.js +3136 -3121
- data/app/assets/javascripts/katello/locale/nl_NL/katello.js +3116 -3101
- data/app/assets/javascripts/katello/locale/or/katello.js +3137 -3122
- data/app/assets/javascripts/katello/locale/pa/katello.js +3136 -3121
- data/app/assets/javascripts/katello/locale/pl/katello.js +3210 -3195
- data/app/assets/javascripts/katello/locale/pl_PL/katello.js +3008 -2993
- data/app/assets/javascripts/katello/locale/pt/katello.js +3009 -2994
- data/app/assets/javascripts/katello/locale/pt_BR/katello.js +5362 -5368
- data/app/assets/javascripts/katello/locale/ro/katello.js +3008 -2993
- data/app/assets/javascripts/katello/locale/ro_RO/katello.js +3008 -2993
- data/app/assets/javascripts/katello/locale/ru/katello.js +4638 -4641
- data/app/assets/javascripts/katello/locale/sl/katello.js +3051 -3036
- data/app/assets/javascripts/katello/locale/sv_SE/katello.js +3156 -3144
- data/app/assets/javascripts/katello/locale/ta/katello.js +3365 -3350
- data/app/assets/javascripts/katello/locale/ta_IN/katello.js +3121 -3106
- data/app/assets/javascripts/katello/locale/te/katello.js +3136 -3121
- data/app/assets/javascripts/katello/locale/tr/katello.js +3025 -3010
- data/app/assets/javascripts/katello/locale/vi/katello.js +3008 -2993
- data/app/assets/javascripts/katello/locale/vi_VN/katello.js +3008 -2993
- data/app/assets/javascripts/katello/locale/zh/katello.js +3008 -2993
- data/app/assets/javascripts/katello/locale/zh_CN/katello.js +5968 -5977
- data/app/assets/javascripts/katello/locale/zh_TW/katello.js +4694 -4697
- data/app/assets/javascripts/katello/sync_management/sync_management.js +1 -0
- data/app/controllers/katello/api/registry/registry_proxies_controller.rb +51 -124
- data/app/controllers/katello/api/rhsm/candlepin_dynflow_proxy_controller.rb +12 -20
- data/app/controllers/katello/api/v2/activation_keys_controller.rb +10 -4
- data/app/controllers/katello/api/v2/capsule_content_controller.rb +24 -0
- data/app/controllers/katello/api/v2/content_view_versions_controller.rb +9 -2
- data/app/controllers/katello/api/v2/debs_controller.rb +1 -1
- data/app/controllers/katello/api/v2/errata_controller.rb +1 -1
- data/app/controllers/katello/api/v2/host_subscriptions_controller.rb +12 -4
- data/app/controllers/katello/api/v2/hosts_bulk_actions_controller.rb +3 -3
- data/app/controllers/katello/api/v2/organizations_controller.rb +0 -11
- data/app/controllers/katello/api/v2/packages_controller.rb +1 -1
- data/app/controllers/katello/api/v2/products_bulk_actions_controller.rb +1 -1
- data/app/controllers/katello/api/v2/repositories_controller.rb +18 -12
- data/app/controllers/katello/api/v2/repository_sets_controller.rb +2 -1
- data/app/controllers/katello/api/v2/simple_content_access_controller.rb +9 -22
- data/app/controllers/katello/concerns/api/v2/authorization.rb +1 -1
- data/app/helpers/katello/concerns/dashboard_helper_extensions.rb +0 -10
- data/app/helpers/katello/hosts_and_hostgroups_helper.rb +14 -2
- data/app/helpers/katello/katello_urls_helper.rb +26 -1
- data/app/helpers/katello/subscription_mailer_helper.rb +1 -1
- data/app/jobs/create_manifest_expire_soon_warning_notifications.rb +11 -0
- data/app/lib/actions/candlepin/owner/regenerate_upstream_identity_cert.rb +21 -0
- data/app/lib/actions/katello/capsule_content/sync.rb +1 -1
- data/app/lib/actions/katello/capsule_content/verify_checksum.rb +75 -0
- data/app/lib/actions/katello/content_view/promote.rb +1 -1
- data/app/lib/actions/katello/content_view/publish.rb +1 -1
- data/app/lib/actions/katello/content_view_version/verify_checksum.rb +29 -0
- data/app/lib/actions/katello/host/hypervisors_update.rb +1 -0
- data/app/lib/actions/katello/host/update_content_view.rb +2 -2
- data/app/lib/actions/katello/organization/manifest_import.rb +5 -0
- data/app/lib/actions/katello/organization/manifest_refresh.rb +3 -0
- data/app/lib/actions/katello/repository/metadata_generate.rb +7 -1
- data/app/lib/actions/katello/repository/remove_content.rb +1 -0
- data/app/lib/actions/katello/repository/sync.rb +2 -1
- data/app/lib/actions/katello/repository/upload_files.rb +1 -0
- data/app/lib/actions/pulp3/capsule_content/verify_checksum.rb +27 -0
- data/app/lib/actions/pulp3/orchestration/content_view_version/export_repository.rb +7 -9
- data/app/lib/actions/pulp3/orchestration/content_view_version/syncable_export.rb +5 -4
- data/app/lib/katello/concerns/base_template_scope_extensions.rb +7 -2
- data/app/lib/katello/errors.rb +4 -0
- data/app/lib/katello/http_resource.rb +6 -1
- data/app/lib/katello/resources/candlepin/consumer.rb +1 -1
- data/app/lib/katello/resources/candlepin/upstream_consumer.rb +18 -6
- data/app/lib/katello/resources/candlepin/upstream_job.rb +1 -1
- data/app/lib/katello/resources/cdn.rb +4 -13
- data/app/lib/katello/resources/registry.rb +25 -0
- data/app/mailers/katello/subscription_mailer.rb +3 -6
- data/app/models/katello/candlepin/repository_mapper.rb +1 -1
- data/app/models/katello/concerns/organization_extensions.rb +42 -3
- data/app/models/katello/content_view.rb +28 -0
- data/app/models/katello/content_view_environment_content_facet.rb +4 -2
- data/app/models/katello/glue/provider.rb +19 -12
- data/app/models/katello/glue/pulp/repos.rb +3 -8
- data/app/models/katello/host/content_facet.rb +1 -1
- data/app/models/katello/host/subscription_facet.rb +1 -1
- data/app/models/katello/host_collection.rb +12 -3
- data/app/models/katello/ping.rb +1 -1
- data/app/models/katello/repository.rb +33 -0
- data/app/models/katello/root_repository.rb +0 -4
- data/app/services/katello/content_unit_indexer.rb +9 -0
- data/app/services/katello/pulp3/alternate_content_source.rb +6 -8
- data/app/services/katello/pulp3/api/core.rb +13 -0
- data/app/services/katello/pulp3/api/yum.rb +11 -0
- data/app/services/katello/pulp3/docker_manifest.rb +5 -1
- data/app/services/katello/pulp3/repository/generic.rb +1 -1
- data/app/services/katello/pulp3/repository.rb +26 -6
- data/app/services/katello/pulp3/repository_mirror.rb +13 -12
- data/app/services/katello/pulp3/service_common.rb +2 -10
- data/app/services/katello/pulp3/smart_proxy_repository.rb +0 -2
- data/app/services/katello/ui_notifications/subscriptions/manifest_expire_soon_warning.rb +75 -0
- data/app/views/foreman/job_templates/update_package_-_katello_ansible_default.erb +5 -1
- data/app/views/foreman/job_templates/update_packages_by_search_query_-_katello_ansible_default.erb +2 -2
- data/app/views/foreman/job_templates/upload_profile.erb +16 -0
- data/app/views/katello/api/v2/content_view_filter_rules/show.json.rabl +9 -0
- data/app/views/katello/api/v2/docker_manifests/show.json.rabl +1 -0
- data/app/views/katello/api/v2/hosts/host_collections.json.rabl +5 -1
- data/app/views/katello/api/v2/organizations/show.json.rabl +9 -1
- data/app/views/katello/hosts/_errata_counts.html.erb +1 -1
- data/app/views/overrides/activation_keys/_host_environment_select.html.erb +1 -1
- data/app/views/overrides/activation_keys/_host_media_type_select.html.erb +15 -5
- data/app/views/overrides/activation_keys/_host_tab_pane.html.erb +1 -29
- data/config/routes/api/registry.rb +4 -8
- data/config/routes/api/v2.rb +2 -0
- data/db/migrate/20240423112842_add_fields_to_katello_docker_manifest.rb +8 -0
- data/db/migrate/20240502192021_change_katello_repository_rpms_id_seq_to_big_int.rb +9 -0
- data/db/seeds.d/109-katello-notification-blueprints.rb +6 -0
- data/engines/bastion_katello/app/assets/javascripts/bastion_katello/activation-keys/details/activation-key-repository-sets.controller.js +3 -3
- data/engines/bastion_katello/app/assets/javascripts/bastion_katello/content-credentials/new/views/new-content-credential.html +2 -1
- data/engines/bastion_katello/app/assets/javascripts/bastion_katello/content-hosts/details/content-host-repository-sets.controller.js +3 -3
- data/engines/bastion_katello/app/assets/javascripts/bastion_katello/i18n/bastion_katello.pot +0 -15
- data/engines/bastion_katello/app/assets/javascripts/bastion_katello/products/details/repositories/details/views/repository-info.html +8 -6
- data/engines/bastion_katello/app/assets/javascripts/bastion_katello/products/details/repositories/new/views/new-repository.html +12 -10
- data/lib/katello/permission_creator.rb +3 -3
- data/lib/katello/permissions/registry_permissions.rb +4 -7
- data/lib/katello/plugin.rb +10 -16
- data/lib/katello/repository_types/ostree.rb +7 -0
- data/lib/katello/scheduled_jobs.rb +7 -1
- data/lib/katello/tasks/clean_backend_objects.rake +1 -1
- data/lib/katello/tasks/repository.rake +22 -0
- data/lib/katello/version.rb +1 -1
- data/locale/action_names.rb +4 -3
- data/locale/bn/katello.po +166 -151
- data/locale/bn_IN/katello.po +166 -151
- data/locale/ca/katello.po +166 -151
- data/locale/cs/katello.po +166 -151
- data/locale/cs_CZ/LC_MESSAGES/katello.mo +0 -0
- data/locale/cs_CZ/katello.po +172 -157
- data/locale/de/LC_MESSAGES/katello.mo +0 -0
- data/locale/de/katello.po +178 -163
- data/locale/de_AT/katello.po +166 -151
- data/locale/de_DE/katello.po +166 -151
- data/locale/el/katello.po +166 -151
- data/locale/en/katello.po +166 -151
- data/locale/en_GB/katello.po +166 -151
- data/locale/en_US/katello.po +166 -151
- data/locale/es/LC_MESSAGES/katello.mo +0 -0
- data/locale/es/katello.po +178 -163
- data/locale/et_EE/katello.po +166 -151
- data/locale/fr/LC_MESSAGES/katello.mo +0 -0
- data/locale/fr/katello.po +179 -164
- data/locale/gl/katello.po +166 -151
- data/locale/gu/katello.po +166 -151
- data/locale/he_IL/katello.po +166 -151
- data/locale/hi/katello.po +166 -151
- data/locale/id/katello.po +166 -151
- data/locale/it/LC_MESSAGES/katello.mo +0 -0
- data/locale/it/katello.po +169 -154
- data/locale/ja/LC_MESSAGES/katello.mo +0 -0
- data/locale/ja/katello.po +179 -164
- data/locale/ka/LC_MESSAGES/katello.mo +0 -0
- data/locale/ka/katello.po +177 -162
- data/locale/katello.pot +1119 -1062
- data/locale/kn/katello.po +166 -151
- data/locale/ko/LC_MESSAGES/katello.mo +0 -0
- data/locale/ko/katello.po +174 -159
- data/locale/ml_IN/katello.po +166 -151
- data/locale/mr/katello.po +166 -151
- data/locale/nl_NL/katello.po +166 -151
- data/locale/or/katello.po +166 -151
- data/locale/pa/katello.po +166 -151
- data/locale/pl/katello.po +166 -151
- data/locale/pl_PL/katello.po +166 -151
- data/locale/pt/katello.po +166 -151
- data/locale/pt_BR/LC_MESSAGES/katello.mo +0 -0
- data/locale/pt_BR/katello.po +178 -163
- data/locale/ro/katello.po +166 -151
- data/locale/ro_RO/katello.po +166 -151
- data/locale/ru/LC_MESSAGES/katello.mo +0 -0
- data/locale/ru/katello.po +171 -156
- data/locale/sl/katello.po +166 -151
- data/locale/sv_SE/katello.po +166 -151
- data/locale/ta/katello.po +166 -151
- data/locale/ta_IN/katello.po +166 -151
- data/locale/te/katello.po +166 -151
- data/locale/tr/katello.po +166 -151
- data/locale/vi/katello.po +166 -151
- data/locale/vi_VN/katello.po +166 -151
- data/locale/zh/katello.po +166 -151
- data/locale/zh_CN/LC_MESSAGES/katello.mo +0 -0
- data/locale/zh_CN/katello.po +179 -164
- data/locale/zh_TW/LC_MESSAGES/katello.mo +0 -0
- data/locale/zh_TW/katello.po +171 -156
- data/webpack/ForemanColumnExtensions/index.js +129 -0
- data/webpack/components/ActivationKeysSearch/ActivationKeysSearch.test.js +28 -0
- data/webpack/components/ActivationKeysSearch/index.js +222 -0
- data/webpack/components/Table/TableWrapper.js +14 -0
- data/webpack/components/extensions/HostDetails/ActionsBar/index.js +1 -1
- data/webpack/components/extensions/HostDetails/Tabs/PackagesTab/PackagesTab.js +1 -1
- data/webpack/components/extensions/HostDetails/Tabs/__tests__/packageInstallModal.test.js +1 -0
- data/webpack/components/extensions/HostDetails/Tabs/__tests__/packagesTab.test.js +1 -0
- data/webpack/components/extensions/Hosts/ActionsBar/index.js +20 -1
- data/webpack/components/extensions/Hosts/BulkActions/BulkChangeHostCVModal/BulkChangeHostCVModal.js +220 -0
- data/webpack/components/extensions/Hosts/BulkActions/BulkChangeHostCVModal/actions.js +23 -0
- data/webpack/components/extensions/Hosts/BulkActions/BulkChangeHostCVModal/index.js +25 -0
- data/webpack/components/extensions/Hosts/BulkActions/__tests__/bulkChangeHostCVModal.test.js +133 -0
- data/webpack/global_index.js +19 -0
- data/webpack/scenes/ContentViews/Details/ComponentContentViews/ContentViewComponents.js +6 -3
- data/webpack/scenes/ContentViews/Publish/CVPublishForm.js +1 -1
- data/webpack/scenes/ContentViews/Publish/__tests__/publishContentView.test.js +30 -0
- data/webpack/scenes/Hosts/ChangeContentSource/actions.js +3 -1
- data/webpack/scenes/Hosts/ChangeContentSource/components/ContentSourceForm.js +63 -25
- data/webpack/scenes/Hosts/ChangeContentSource/index.js +24 -16
- data/webpack/scenes/RedHatRepositories/__tests__/__snapshots__/RedHatRepositoriesPage.test.js.snap +1 -0
- data/webpack/scenes/Subscriptions/Manifest/ManageManifestModal.js +64 -5
- data/webpack/scenes/Subscriptions/UpstreamSubscriptions/UpstreamSubscriptionsPage.js +16 -13
- data/webpack/scenes/Subscriptions/UpstreamSubscriptions/__tests__/__snapshots__/UpstreamSubscriptionsPage.test.js.snap +14 -8
- data/webpack/scenes/Subscriptions/__tests__/__snapshots__/SubscriptionsPage.test.js.snap +1 -0
- data/webpack/scenes/Subscriptions/components/SubscriptionsToolbar/SubscriptionsToolbar.js +1 -1
- metadata +59 -40
- data/app/assets/javascripts/katello/hosts/activation_key_edit.js +0 -167
- data/app/lib/actions/katello/host/upload_package_profile.rb +0 -45
- data/app/lib/actions/katello/host/upload_profiles.rb +0 -47
data/webpack/components/extensions/Hosts/BulkActions/BulkChangeHostCVModal/BulkChangeHostCVModal.js
ADDED
@@ -0,0 +1,220 @@
|
|
1
|
+
import React, { useState } from 'react';
|
2
|
+
import PropTypes from 'prop-types';
|
3
|
+
import { useDispatch, useSelector } from 'react-redux';
|
4
|
+
import { FormattedMessage } from 'react-intl';
|
5
|
+
import { Modal, Button, Alert, TextContent, Text, TextVariants } from '@patternfly/react-core';
|
6
|
+
import { translate as __ } from 'foremanReact/common/I18n';
|
7
|
+
import { STATUS } from 'foremanReact/constants';
|
8
|
+
import { useAPI } from 'foremanReact/common/hooks/API/APIHooks';
|
9
|
+
import { selectAPIStatus } from 'foremanReact/redux/API/APISelectors';
|
10
|
+
import { ENVIRONMENT_PATHS_KEY } from '../../../../../scenes/ContentViews/components/EnvironmentPaths/EnvironmentPathConstants';
|
11
|
+
import EnvironmentPaths from '../../../../../scenes/ContentViews/components/EnvironmentPaths/EnvironmentPaths';
|
12
|
+
import ContentViewSelect from '../../../../../scenes/ContentViews/components/ContentViewSelect/ContentViewSelect';
|
13
|
+
import ContentViewSelectOption from '../../../../../scenes/ContentViews/components/ContentViewSelect/ContentViewSelectOption';
|
14
|
+
import api from '../../../../../services/api';
|
15
|
+
import getContentViews from '../../../../../scenes/ContentViews/ContentViewsActions';
|
16
|
+
import { selectContentViews, selectContentViewStatus } from '../../../../../scenes/ContentViews/ContentViewSelectors';
|
17
|
+
import { bulkUpdateHostContentViewAndEnvironment } from './actions';
|
18
|
+
import { getCVPlaceholderText } from '../../../../../scenes/ContentViews/components/ContentViewSelect/helpers';
|
19
|
+
import HOST_CV_AND_ENV_KEY from '../../../HostDetails/Cards/ContentViewDetailsCard/HostContentViewConstants';
|
20
|
+
|
21
|
+
const ENV_PATH_OPTIONS = { key: ENVIRONMENT_PATHS_KEY };
|
22
|
+
|
23
|
+
const BulkChangeHostCVModal = ({
|
24
|
+
isOpen,
|
25
|
+
closeModal,
|
26
|
+
selectedCount,
|
27
|
+
orgId,
|
28
|
+
fetchBulkParams,
|
29
|
+
}) => {
|
30
|
+
const [selectedLifecycleEnv, setSelectedLifecycleEnv]
|
31
|
+
= useState([]);
|
32
|
+
|
33
|
+
const [selectedContentView, setSelectedContentView] = useState(null);
|
34
|
+
const [cvSelectOpen, setCVSelectOpen] = useState(false);
|
35
|
+
const dispatch = useDispatch();
|
36
|
+
const contentViewsInEnvResponse = useSelector(state => selectContentViews(state, '_FOR_DEFAULT_ENV'));
|
37
|
+
const { results } = contentViewsInEnvResponse;
|
38
|
+
const contentViewsInEnvStatus = useSelector(state => selectContentViewStatus(state, '_FOR_DEFAULT_ENV'));
|
39
|
+
const hostUpdateStatus = useSelector(state => selectAPIStatus(state, HOST_CV_AND_ENV_KEY));
|
40
|
+
const pathsUrl = `/organizations/${orgId}/environments/paths?permission_type=promotable`;
|
41
|
+
useAPI( // No TableWrapper here, so we can useAPI from Foreman
|
42
|
+
'get',
|
43
|
+
api.getApiUrl(pathsUrl),
|
44
|
+
ENV_PATH_OPTIONS,
|
45
|
+
);
|
46
|
+
const selectedContentViewId = results?.find(cv => cv.name === selectedContentView)?.id;
|
47
|
+
|
48
|
+
const handleModalClose = () => {
|
49
|
+
setCVSelectOpen(false);
|
50
|
+
setSelectedContentView(null);
|
51
|
+
setSelectedLifecycleEnv([]);
|
52
|
+
closeModal();
|
53
|
+
};
|
54
|
+
|
55
|
+
const selectedEnv = selectedLifecycleEnv?.[0];
|
56
|
+
const selectedEnvId = selectedEnv?.id;
|
57
|
+
|
58
|
+
const handleCVSelect = (event, selection) => {
|
59
|
+
setSelectedContentView(selection);
|
60
|
+
setCVSelectOpen(false);
|
61
|
+
};
|
62
|
+
|
63
|
+
const handleEnvSelect = (selection) => {
|
64
|
+
dispatch(getContentViews({
|
65
|
+
environment_id: selection[0].id,
|
66
|
+
include_default: true,
|
67
|
+
full_result: true,
|
68
|
+
order: 'default DESC', // show Default Organization View first
|
69
|
+
}, '_FOR_DEFAULT_ENV'));
|
70
|
+
setSelectedContentView(null);
|
71
|
+
setSelectedLifecycleEnv(selection);
|
72
|
+
};
|
73
|
+
const { results: contentViewsInEnv = [] } = contentViewsInEnvResponse;
|
74
|
+
const canSave = !!(selectedContentView && selectedLifecycleEnv.length);
|
75
|
+
|
76
|
+
const handleSave = () => {
|
77
|
+
const requestBody = {
|
78
|
+
content_view_id: selectedContentViewId,
|
79
|
+
environment_id: selectedEnvId,
|
80
|
+
organization_id: orgId,
|
81
|
+
included: {
|
82
|
+
search: fetchBulkParams(),
|
83
|
+
},
|
84
|
+
};
|
85
|
+
dispatch(bulkUpdateHostContentViewAndEnvironment(
|
86
|
+
requestBody, fetchBulkParams(),
|
87
|
+
handleModalClose, handleModalClose,
|
88
|
+
));
|
89
|
+
};
|
90
|
+
|
91
|
+
const cvPlaceholderText = getCVPlaceholderText({
|
92
|
+
environments: selectedLifecycleEnv,
|
93
|
+
cvSelectOptions: contentViewsInEnv,
|
94
|
+
contentViewsStatus: contentViewsInEnvStatus,
|
95
|
+
});
|
96
|
+
|
97
|
+
const stillLoading =
|
98
|
+
(contentViewsInEnvStatus === STATUS.PENDING || hostUpdateStatus === STATUS.PENDING);
|
99
|
+
const noContentViewsAvailable =
|
100
|
+
(contentViewsInEnv.length === 0 || selectedLifecycleEnv.length === 0);
|
101
|
+
|
102
|
+
const modalActions = ([
|
103
|
+
<Button
|
104
|
+
key="add"
|
105
|
+
ouiaId="bulk-change-host-cv-modal-add-button"
|
106
|
+
variant="primary"
|
107
|
+
onClick={handleSave}
|
108
|
+
isDisabled={!canSave || hostUpdateStatus === STATUS.PENDING}
|
109
|
+
isLoading={hostUpdateStatus === STATUS.PENDING}
|
110
|
+
>
|
111
|
+
{__('Save')}
|
112
|
+
</Button>,
|
113
|
+
<Button key="cancel" ouiaId="change-host-cv-modal-cancel-button" variant="link" onClick={handleModalClose}>
|
114
|
+
Cancel
|
115
|
+
</Button>,
|
116
|
+
]);
|
117
|
+
return (
|
118
|
+
<Modal
|
119
|
+
isOpen={isOpen}
|
120
|
+
onClose={handleModalClose}
|
121
|
+
onEscapePress={handleModalClose}
|
122
|
+
title={__('Edit content view environments')}
|
123
|
+
width="50%"
|
124
|
+
position="top"
|
125
|
+
actions={modalActions}
|
126
|
+
id="bulk-change-host-cv-modal"
|
127
|
+
key="bulk-change-host-cv-modal"
|
128
|
+
ouiaId="bulk-change-host-cv-modal"
|
129
|
+
>
|
130
|
+
<TextContent>
|
131
|
+
<Text
|
132
|
+
ouiaId="bulk-change-cv-options-description"
|
133
|
+
>
|
134
|
+
<FormattedMessage
|
135
|
+
defaultMessage={__('This will update the content view environments for {hosts}.')}
|
136
|
+
values={{
|
137
|
+
hosts: (
|
138
|
+
<strong>
|
139
|
+
<FormattedMessage
|
140
|
+
defaultMessage="{count, plural, one {# {singular}} other {# {plural}}}"
|
141
|
+
values={{
|
142
|
+
count: selectedCount,
|
143
|
+
singular: __('selected host'),
|
144
|
+
plural: __('selected hosts'),
|
145
|
+
}}
|
146
|
+
id="ccs-options-i18n"
|
147
|
+
/>
|
148
|
+
</strong>
|
149
|
+
),
|
150
|
+
}}
|
151
|
+
id="bulk-change-cv-options-description-i18n"
|
152
|
+
/>
|
153
|
+
</Text>
|
154
|
+
</TextContent>
|
155
|
+
{contentViewsInEnvStatus === STATUS.RESOLVED &&
|
156
|
+
!!selectedLifecycleEnv.length && contentViewsInEnv.length === 0 &&
|
157
|
+
<Alert
|
158
|
+
ouiaId="no-cv-alert"
|
159
|
+
variant="warning"
|
160
|
+
isInline
|
161
|
+
title={__('No content views available for the selected environment')}
|
162
|
+
style={{ marginBottom: '1rem' }}
|
163
|
+
>
|
164
|
+
<a href="/content_views">{__('View the Content Views page')}</a>
|
165
|
+
{__(' to manage and promote content views, or select a different environment.')}
|
166
|
+
</Alert>
|
167
|
+
}
|
168
|
+
<EnvironmentPaths
|
169
|
+
userCheckedItems={selectedLifecycleEnv}
|
170
|
+
setUserCheckedItems={handleEnvSelect}
|
171
|
+
publishing={false}
|
172
|
+
multiSelect={false}
|
173
|
+
headerText={__('Select environment')}
|
174
|
+
isDisabled={hostUpdateStatus === STATUS.PENDING}
|
175
|
+
/>
|
176
|
+
<ContentViewSelect
|
177
|
+
selections={selectedContentView}
|
178
|
+
onClear={() => setSelectedContentView(null)}
|
179
|
+
onSelect={handleCVSelect}
|
180
|
+
isOpen={cvSelectOpen}
|
181
|
+
isDisabled={stillLoading || noContentViewsAvailable}
|
182
|
+
onToggle={isExpanded => setCVSelectOpen(isExpanded)}
|
183
|
+
placeholderText={cvPlaceholderText}
|
184
|
+
>
|
185
|
+
{(contentViewsInEnv.length !== 0 && selectedLifecycleEnv.length !== 0) &&
|
186
|
+
contentViewsInEnv?.map(cv => (
|
187
|
+
<ContentViewSelectOption
|
188
|
+
key={cv.id}
|
189
|
+
value={cv.name}
|
190
|
+
cv={cv}
|
191
|
+
env={selectedLifecycleEnv[0]}
|
192
|
+
/>
|
193
|
+
))}
|
194
|
+
</ContentViewSelect>
|
195
|
+
<hr />
|
196
|
+
<TextContent>
|
197
|
+
<Text component={TextVariants.small} ouiaId="profile-upload-reminder-text">
|
198
|
+
{__('Errata and package information will be updated at the next host check-in or package action.')}
|
199
|
+
</Text>
|
200
|
+
</TextContent>
|
201
|
+
<hr />
|
202
|
+
</Modal>
|
203
|
+
);
|
204
|
+
};
|
205
|
+
|
206
|
+
BulkChangeHostCVModal.propTypes = {
|
207
|
+
isOpen: PropTypes.bool,
|
208
|
+
closeModal: PropTypes.func,
|
209
|
+
selectedCount: PropTypes.number.isRequired,
|
210
|
+
orgId: PropTypes.number.isRequired,
|
211
|
+
fetchBulkParams: PropTypes.func.isRequired,
|
212
|
+
};
|
213
|
+
|
214
|
+
BulkChangeHostCVModal.defaultProps = {
|
215
|
+
isOpen: false,
|
216
|
+
closeModal: () => {},
|
217
|
+
};
|
218
|
+
|
219
|
+
|
220
|
+
export default BulkChangeHostCVModal;
|
@@ -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
|
+
import HOST_CV_AND_ENV_KEY from '../../../HostDetails/Cards/ContentViewDetailsCard/HostContentViewConstants';
|
6
|
+
|
7
|
+
export const bulkUpdateHostContentViewAndEnvironment =
|
8
|
+
(params, bulkParams, handleSuccess, handleError) => put({
|
9
|
+
type: API_OPERATIONS.PUT,
|
10
|
+
key: HOST_CV_AND_ENV_KEY,
|
11
|
+
url: foremanApi.getApiUrl('/hosts/bulk/environment_content_view'),
|
12
|
+
...bulkParams,
|
13
|
+
successToast: () => __('Host content view environments 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 bulkUpdateHostContentViewAndEnvironment;
|
@@ -0,0 +1,25 @@
|
|
1
|
+
import React, { useContext } from 'react';
|
2
|
+
import { useForemanOrganization } from 'foremanReact/Root/Context/ForemanContext';
|
3
|
+
import { ForemanActionsBarContext } from 'foremanReact/components/HostDetails/ActionsBar';
|
4
|
+
import { useForemanModal } from 'foremanReact/components/ForemanModal/ForemanModalHooks';
|
5
|
+
import BulkChangeHostCVModal from './BulkChangeHostCVModal';
|
6
|
+
|
7
|
+
const BulkChangeHostCVModalScene = () => {
|
8
|
+
const org = useForemanOrganization();
|
9
|
+
const { selectedCount, fetchBulkParams } = useContext(ForemanActionsBarContext);
|
10
|
+
const { modalOpen, setModalClosed } = useForemanModal({ id: 'bulk-change-cv-modal' });
|
11
|
+
|
12
|
+
return (
|
13
|
+
<BulkChangeHostCVModal
|
14
|
+
key="bulk-change-cv-modal"
|
15
|
+
selectedCount={selectedCount}
|
16
|
+
fetchBulkParams={fetchBulkParams}
|
17
|
+
isOpen={modalOpen}
|
18
|
+
closeModal={setModalClosed}
|
19
|
+
orgId={org?.id}
|
20
|
+
/>
|
21
|
+
|
22
|
+
);
|
23
|
+
};
|
24
|
+
|
25
|
+
export default BulkChangeHostCVModalScene;
|
@@ -0,0 +1,133 @@
|
|
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 BulkChangeHostCVModal from '../BulkChangeHostCVModal/BulkChangeHostCVModal.js';
|
5
|
+
import mockEnvPaths from '../../../HostDetails/Cards/ContentViewDetailsCard/__tests__/envPaths.fixtures.json';
|
6
|
+
import mockContentViews from '../../../HostDetails/Cards/ContentViewDetailsCard/__tests__/contentViews.fixtures.json';
|
7
|
+
import HOST_CV_AND_ENV_KEY from '../../../HostDetails/Cards/ContentViewDetailsCard/HostContentViewConstants';
|
8
|
+
import { assertNockRequest, nockInstance } from '../../../../../test-utils/nockWrapper';
|
9
|
+
import katelloApi from '../../../../../services/api';
|
10
|
+
|
11
|
+
const contentViews = katelloApi.getApiUrl('/content_views');
|
12
|
+
const renderOptions = () => ({
|
13
|
+
apiNamespace: HOST_CV_AND_ENV_KEY,
|
14
|
+
initialState: {
|
15
|
+
API: {
|
16
|
+
HOST_DETAILS: {
|
17
|
+
response: {
|
18
|
+
id: 1,
|
19
|
+
name: 'test-host',
|
20
|
+
content_facet_attributes: {
|
21
|
+
content_view_id: 1,
|
22
|
+
lifecycle_environment_id: 1,
|
23
|
+
},
|
24
|
+
organization_id: 1,
|
25
|
+
},
|
26
|
+
status: 'RESOLVED',
|
27
|
+
},
|
28
|
+
ENVIRONMENT_PATHS: {
|
29
|
+
response: mockEnvPaths,
|
30
|
+
status: 'RESOLVED',
|
31
|
+
},
|
32
|
+
},
|
33
|
+
},
|
34
|
+
});
|
35
|
+
|
36
|
+
let firstEnvPath;
|
37
|
+
let firstCV;
|
38
|
+
let secondCV;
|
39
|
+
let firstEnv;
|
40
|
+
|
41
|
+
const cvQuery = {
|
42
|
+
organization_id: 1,
|
43
|
+
include_permissions: true,
|
44
|
+
include_default: true,
|
45
|
+
environment_id: 1,
|
46
|
+
full_result: true,
|
47
|
+
order: 'default DESC',
|
48
|
+
};
|
49
|
+
|
50
|
+
beforeEach(() => {
|
51
|
+
const { results } = mockEnvPaths;
|
52
|
+
[firstEnvPath] = results;
|
53
|
+
const { environments: envResults } = firstEnvPath;
|
54
|
+
[firstEnv] = envResults;
|
55
|
+
const { results: cvResults } = mockContentViews;
|
56
|
+
[firstCV, secondCV] = cvResults;
|
57
|
+
});
|
58
|
+
|
59
|
+
jest.mock('foremanReact/common/hooks/API/APIHooks', () => ({
|
60
|
+
useAPI: jest.fn(),
|
61
|
+
}));
|
62
|
+
|
63
|
+
test('Displays environment paths', async (done) => {
|
64
|
+
const jsx = (
|
65
|
+
<BulkChangeHostCVModal
|
66
|
+
isOpen
|
67
|
+
closeModal={jest.fn()}
|
68
|
+
selectedCount={1}
|
69
|
+
fetchBulkParams={() => 'id ^ 1'}
|
70
|
+
orgId={1}
|
71
|
+
/>
|
72
|
+
);
|
73
|
+
const { getAllByText }
|
74
|
+
= renderWithRedux(jsx, renderOptions());
|
75
|
+
|
76
|
+
await patientlyWaitFor(() =>
|
77
|
+
expect(getAllByText(firstEnv.name)[0]).toBeInTheDocument());
|
78
|
+
done();
|
79
|
+
});
|
80
|
+
|
81
|
+
test('Select an env > call CV API > select a CV > Save button is enabled', async (done) => {
|
82
|
+
const contentViewsScope = nockInstance
|
83
|
+
.get(contentViews)
|
84
|
+
.query(cvQuery)
|
85
|
+
.reply(200, mockContentViews);
|
86
|
+
|
87
|
+
const jsx = (
|
88
|
+
<BulkChangeHostCVModal
|
89
|
+
isOpen
|
90
|
+
closeModal={jest.fn()}
|
91
|
+
selectedCount={1}
|
92
|
+
fetchBulkParams={() => 'id ^ 1'}
|
93
|
+
orgId={1}
|
94
|
+
/>
|
95
|
+
);
|
96
|
+
const {
|
97
|
+
getAllByText, getByText,
|
98
|
+
findByPlaceholderText, getAllByRole,
|
99
|
+
} = renderWithRedux(jsx, renderOptions());
|
100
|
+
|
101
|
+
await patientlyWaitFor(() => {
|
102
|
+
const envLabel = getAllByText(firstEnv.name)[0];
|
103
|
+
expect(envLabel).toBeInTheDocument();
|
104
|
+
});
|
105
|
+
|
106
|
+
const envRadio = getAllByRole('radio', { name: firstEnv.name })[0];
|
107
|
+
expect(envRadio).toBeInTheDocument();
|
108
|
+
|
109
|
+
await act(async () => {
|
110
|
+
userEvent.click(envRadio); // Select the Library environment
|
111
|
+
|
112
|
+
const cvDropdown = await findByPlaceholderText('Select a content view');
|
113
|
+
expect(cvDropdown).toBeInTheDocument();
|
114
|
+
|
115
|
+
userEvent.click(cvDropdown); // Open the CV dropdown
|
116
|
+
|
117
|
+
|
118
|
+
[firstCV, secondCV].forEach((cv) => {
|
119
|
+
expect(getByText(cv.name)).toBeInTheDocument(); // the content view names should be showing
|
120
|
+
});
|
121
|
+
|
122
|
+
|
123
|
+
userEvent.click(getByText(secondCV.name)); // Select the second content view
|
124
|
+
});
|
125
|
+
|
126
|
+
// find the Save button and assert that it is enabled
|
127
|
+
const saveButton = getAllByRole('button', { name: 'Save' })[0];
|
128
|
+
expect(saveButton).toBeInTheDocument();
|
129
|
+
expect(saveButton).toHaveAttribute('aria-disabled', 'false');
|
130
|
+
|
131
|
+
assertNockRequest(contentViewsScope, done);
|
132
|
+
act(done);
|
133
|
+
});
|
data/webpack/global_index.js
CHANGED
@@ -2,7 +2,10 @@ import React from 'react';
|
|
2
2
|
import { addGlobalFill } from 'foremanReact/components/common/Fill/GlobalFill';
|
3
3
|
import { registerReducer } from 'foremanReact/common/MountingService';
|
4
4
|
import { translate as __ } from 'foremanReact/common/I18n';
|
5
|
+
import { registerColumns } from 'foremanReact/components/HostsIndex/Columns/core';
|
6
|
+
import componentRegistry from 'foremanReact/components/componentRegistry';
|
5
7
|
|
8
|
+
import hostsIndexColumnExtensions from './ForemanColumnExtensions/index';
|
6
9
|
import SystemStatuses from './components/extensions/about';
|
7
10
|
import {
|
8
11
|
RegistrationCommands,
|
@@ -29,6 +32,10 @@ import HostDetailsActionsBar from './components/extensions/HostDetails/ActionsBa
|
|
29
32
|
import HostsIndexActionsBar from './components/extensions/Hosts/ActionsBar';
|
30
33
|
import RecentCommunicationCardExtensions from './components/extensions/HostDetails/DetailsTabCards/RecentCommunicationCardExtensions';
|
31
34
|
import SystemPurposeCard from './components/extensions/HostDetails/Cards/SystemPurposeCard/SystemPurposeCard';
|
35
|
+
import BulkChangeHostCVModal from './components/extensions/Hosts/BulkActions/BulkChangeHostCVModal/index.js';
|
36
|
+
|
37
|
+
|
38
|
+
import ActivationKeysSearch from './components/ActivationKeysSearch';
|
32
39
|
|
33
40
|
registerReducer('katelloExtends', extendReducer);
|
34
41
|
registerReducer('katello', rootReducer);
|
@@ -80,3 +87,15 @@ addGlobalFill(
|
|
80
87
|
);
|
81
88
|
|
82
89
|
addGlobalFill('host-tab-details-cards', 'HW properties', <HwPropertiesCard key="hw-properties" />, 200);
|
90
|
+
|
91
|
+
// Hosts Index page extensions
|
92
|
+
addGlobalFill('_all-hosts-modals', 'BulkChangeHostCVModal', <BulkChangeHostCVModal key="bulk-change-host-cv-modal" />, 100);
|
93
|
+
|
94
|
+
registerColumns(hostsIndexColumnExtensions);
|
95
|
+
|
96
|
+
|
97
|
+
componentRegistry.register({
|
98
|
+
name: 'ActivationKeysSearch',
|
99
|
+
type: ActivationKeysSearch,
|
100
|
+
});
|
101
|
+
|
@@ -5,7 +5,6 @@ import {
|
|
5
5
|
Bullseye, Split, SplitItem, Button, ActionList,
|
6
6
|
ActionListItem, Dropdown, DropdownItem, KebabToggle,
|
7
7
|
} from '@patternfly/react-core';
|
8
|
-
import { Link } from 'react-router-dom';
|
9
8
|
import { TableVariant, fitContent, TableText } from '@patternfly/react-table';
|
10
9
|
import { PencilAltIcon } from '@patternfly/react-icons';
|
11
10
|
import { STATUS } from 'foremanReact/constants';
|
@@ -136,7 +135,7 @@ const ContentViewComponents = ({ cvId, details }) => {
|
|
136
135
|
id: componentCvId, content_view: cv, content_view_version: cvVersion,
|
137
136
|
latest, component_content_view_versions: componentCvVersions,
|
138
137
|
} = componentCV;
|
139
|
-
const { environments, repositories } = cvVersion || {};
|
138
|
+
const { environments, repositories, id: cvVersionId } = cvVersion || {};
|
140
139
|
const {
|
141
140
|
id,
|
142
141
|
name,
|
@@ -171,7 +170,11 @@ const ContentViewComponents = ({ cvId, details }) => {
|
|
171
170
|
</Split>),
|
172
171
|
},
|
173
172
|
{ title: environments ? <ComponentEnvironments {...{ environments }} /> : <InactiveText text={__('Not yet published')} /> },
|
174
|
-
{
|
173
|
+
{
|
174
|
+
title: cvVersionId ?
|
175
|
+
<a href={urlBuilder(`content_views/${id}#/versions/${cvVersionId}/repositories`, '')}>{repositories ? repositories.length : 0}</a> :
|
176
|
+
0,
|
177
|
+
},
|
175
178
|
{
|
176
179
|
title: <AddedStatusLabel added={!!componentCvId} />,
|
177
180
|
},
|
@@ -66,7 +66,7 @@ const CVPublishForm = ({
|
|
66
66
|
</Alert>)
|
67
67
|
}
|
68
68
|
{!duplicateReposAlertDismissed && composite &&
|
69
|
-
(duplicateRepos !== null
|
69
|
+
(duplicateRepos !== null && duplicateRepos.length > 0) &&
|
70
70
|
(
|
71
71
|
<Alert
|
72
72
|
ouiaId="duplicate-repos-alert"
|
@@ -1,6 +1,9 @@
|
|
1
1
|
import React from 'react';
|
2
2
|
import * as reactRedux from 'react-redux';
|
3
3
|
import { renderWithRedux, patientlyWaitFor, fireEvent, act } from 'react-testing-lib-wrapper';
|
4
|
+
import { screen } from '@testing-library/react';
|
5
|
+
import '@testing-library/jest-dom';
|
6
|
+
|
4
7
|
import { nockInstance, assertNockRequest } from '../../../../test-utils/nockWrapper';
|
5
8
|
import api from '../../../../services/api';
|
6
9
|
import PublishContentViewWizard from '../PublishContentViewWizard';
|
@@ -80,6 +83,33 @@ test('Can show wizard with duplicate repository warning for composite CV', async
|
|
80
83
|
assertNockRequest(filterScope, done);
|
81
84
|
});
|
82
85
|
|
86
|
+
test('Can show wizard without duplicate repository warning for composite CV', async (done) => {
|
87
|
+
const cvCompositeDetailsData = cvDetailData;
|
88
|
+
cvCompositeDetailsData.composite = true;
|
89
|
+
cvCompositeDetailsData.duplicate_repositories_to_publish = [];
|
90
|
+
const scope = nockInstance
|
91
|
+
.get(environmentPathsPath)
|
92
|
+
.query(true)
|
93
|
+
.reply(200, environmentPathsData);
|
94
|
+
const filterScope = nockInstance
|
95
|
+
.get(cvFiltersPath)
|
96
|
+
.reply(200, contentViewFilterData);
|
97
|
+
|
98
|
+
const { getByText } = renderWithRedux(<PublishContentViewWizard
|
99
|
+
details={cvCompositeDetailsData}
|
100
|
+
show
|
101
|
+
onClose={() => { }}
|
102
|
+
/>);
|
103
|
+
|
104
|
+
await patientlyWaitFor(() => {
|
105
|
+
expect(getByText('Publish new version - 6.0')).toBeInTheDocument();
|
106
|
+
expect(screen.queryByText('Repositories common to the selected content view versions will merge, resulting in a composite content view that is a union of all content from each of the content view versions.')).not.toBeInTheDocument();
|
107
|
+
});
|
108
|
+
|
109
|
+
assertNockRequest(scope);
|
110
|
+
assertNockRequest(filterScope, done);
|
111
|
+
});
|
112
|
+
|
83
113
|
test('Can show Wizard and show environment paths', async (done) => {
|
84
114
|
const scope = nockInstance
|
85
115
|
.get(environmentPathsPath)
|
@@ -18,7 +18,7 @@ export const getFormData = (hostIds, search) => (post({
|
|
18
18
|
}));
|
19
19
|
|
20
20
|
export const changeContentSource =
|
21
|
-
(environmentId, contentViewId, contentSourceId, hostIds, handleSuccess) =>
|
21
|
+
(environmentId, contentViewId, contentSourceId, hostIds, handleSuccess, successToast) =>
|
22
22
|
put({
|
23
23
|
key: CHANGE_CONTENT_SOURCE,
|
24
24
|
url: foremanUrl('/api/v2/hosts/bulk/change_content_source'),
|
@@ -29,6 +29,7 @@ export const changeContentSource =
|
|
29
29
|
host_ids: hostIds,
|
30
30
|
},
|
31
31
|
errorToast: () => __('Something went wrong while updating the content source. See the logs for more information'),
|
32
|
+
successToast,
|
32
33
|
handleSuccess,
|
33
34
|
});
|
34
35
|
|
@@ -46,6 +47,7 @@ export const getContentViews = environmentId =>
|
|
46
47
|
params: {
|
47
48
|
environment_id: environmentId,
|
48
49
|
full_result: true,
|
50
|
+
order: 'default DESC', // shows the default CV before all other options
|
49
51
|
},
|
50
52
|
errorToast: () => __('Something went wrong while loading the content views. See the logs for more information'),
|
51
53
|
});
|