katello 4.20.0 → 4.20.1
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.
- checksums.yaml +4 -4
- data/app/controllers/katello/api/v2/content_uploads_controller.rb +2 -1
- data/app/controllers/katello/api/v2/host_bootc_images_controller.rb +12 -4
- data/app/lib/katello/resources/cdn.rb +10 -5
- data/app/models/katello/cdn_configuration.rb +4 -2
- data/app/models/katello/host/content_facet.rb +15 -1
- data/app/services/katello/managed_content_medium_provider.rb +1 -1
- data/app/services/katello/pulp3/repository.rb +13 -4
- data/app/views/katello/api/v2/content_credentials/show.json.rabl +3 -3
- data/app/views/katello/api/v2/content_facet/base.json.rabl +4 -0
- data/engines/bastion/app/views/bastion/layouts/assets.html.erb +1 -0
- data/engines/bastion_katello/app/assets/javascripts/bastion_katello/content-hosts/bulk/content-hosts-bulk-errata-modal.controller.js +9 -2
- data/engines/bastion_katello/app/assets/javascripts/bastion_katello/content-hosts/bulk/views/content-hosts-bulk-errata-modal.html +1 -1
- data/engines/bastion_katello/app/assets/javascripts/bastion_katello/debs/details/deb.controller.js +9 -2
- data/engines/bastion_katello/app/assets/javascripts/bastion_katello/debs/details/views/deb-info.html +3 -3
- data/engines/bastion_katello/app/assets/javascripts/bastion_katello/packages/details/package.controller.js +6 -3
- data/lib/katello/version.rb +1 -1
- data/locale/action_names.rb +0 -2
- data/locale/cs/LC_MESSAGES/katello.mo +0 -0
- data/locale/de_AT/LC_MESSAGES/katello.mo +0 -0
- data/locale/en/LC_MESSAGES/katello.mo +0 -0
- data/locale/en_US/LC_MESSAGES/katello.mo +0 -0
- data/locale/et_EE/LC_MESSAGES/katello.mo +0 -0
- data/locale/ml_IN/LC_MESSAGES/katello.mo +0 -0
- data/locale/pl_PL/LC_MESSAGES/katello.mo +0 -0
- data/locale/pt/LC_MESSAGES/katello.mo +0 -0
- data/locale/ro/LC_MESSAGES/katello.mo +0 -0
- data/locale/ro_RO/LC_MESSAGES/katello.mo +0 -0
- data/locale/vi/LC_MESSAGES/katello.mo +0 -0
- data/locale/vi_VN/LC_MESSAGES/katello.mo +0 -0
- data/locale/zh/LC_MESSAGES/katello.mo +0 -0
- data/webpack/components/Bookmark/AddBookmarkModal.js +1 -1
- data/webpack/components/extensions/HostDetails/Tabs/ErrataTab/ErrataTab.js +7 -7
- data/webpack/components/extensions/HostDetails/Tabs/__tests__/errataTab.test.js +9 -107
- data/webpack/scenes/AlternateContentSources/Create/__tests__/contentCredentials.fixtures.json +6 -6
- data/webpack/scenes/ContainerImages/Booted/BootedContainerImagesPage.js +1 -1
- data/webpack/scenes/ContentCredentials/__tests__/contentCredentials.fixtures.js +6 -6
- metadata +3 -3
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 752107902c268ac7230e4ba7c967a1f273c871559b80dd30ff622337d2cb2f56
|
|
4
|
+
data.tar.gz: 514cbd47032ce0940e1246d2cd5b23f290958289858241bfc1e2bff9caa3928f
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: ec64a4c18b636df115542a86fa8874c9db757bde3fac4084f23b8ff0aac7baa51fcaf79d88cd684d5c83862e229f743aca63d5d033b9bec9fef7a762743948af
|
|
7
|
+
data.tar.gz: 6430af999d6bfb5478fab680b5ece3986c12841da4fedb5d7cbce05fd381d6ed96b58b71d89a3df59d436a4d88629faeef4afc18ddd39c4869280028d1890a00
|
|
@@ -15,7 +15,8 @@ module Katello
|
|
|
15
15
|
param :content_type, RepositoryTypeManager.uploadable_content_types(false).map(&:label), :required => false, :desc => N_("content type ('deb', 'file', 'ostree_ref', 'rpm', 'srpm')")
|
|
16
16
|
def create
|
|
17
17
|
fail Katello::Errors::InvalidRepositoryContent, _("Cannot upload Ansible collections.") if @repository.ansible_collection?
|
|
18
|
-
|
|
18
|
+
# params[:size].to_i > 0 confirms if user is trying to upload a docker image.
|
|
19
|
+
fail Katello::Errors::InvalidRepositoryContent, _("Cannot upload container content via Hammer/API. Use podman push instead.") if @repository.docker? && params[:size].to_i > 0
|
|
19
20
|
content_type = params[:content_type] || ::Katello::RepositoryTypeManager.find(@repository.content_type)&.default_managed_content_type&.label
|
|
20
21
|
RepositoryTypeManager.check_content_matches_repo_type!(@repository, content_type)
|
|
21
22
|
if ::Katello::RepositoryTypeManager.generic_content_type?(content_type)
|
|
@@ -10,13 +10,15 @@ module Katello
|
|
|
10
10
|
api :GET, "/hosts/bootc_images", N_("List booted bootc container images for hosts")
|
|
11
11
|
param_group :search, Api::V2::ApiController
|
|
12
12
|
def bootc_images
|
|
13
|
-
params[:sort_by] ||= 'bootc_booted_image'
|
|
14
|
-
params[:sort_order] ||= 'asc'
|
|
15
13
|
if params[:order]
|
|
16
|
-
|
|
14
|
+
parts = params[:order].split(' ')
|
|
15
|
+
params[:sort_by] = sanitize_sort_column(parts[0])
|
|
16
|
+
params[:sort_order] = sanitize_sort_order(parts[1])
|
|
17
17
|
else
|
|
18
|
-
params[:
|
|
18
|
+
params[:sort_by] = sanitize_sort_column(params[:sort_by])
|
|
19
|
+
params[:sort_order] = sanitize_sort_order(params[:sort_order])
|
|
19
20
|
end
|
|
21
|
+
params[:order] = "#{params[:sort_by]} #{params[:sort_order]}"
|
|
20
22
|
per_page = params[:per_page].present? ? params[:per_page].to_i : Setting[:entries_per_page]
|
|
21
23
|
page = params[:page].present? ? params[:page].to_i : 1
|
|
22
24
|
|
|
@@ -38,6 +40,8 @@ module Katello
|
|
|
38
40
|
|
|
39
41
|
private
|
|
40
42
|
|
|
43
|
+
SORTABLE_COLUMNS = %w[bootc_booted_image bootc_booted_digest host_count].freeze
|
|
44
|
+
|
|
41
45
|
def sanitize_sort_order(sort_order)
|
|
42
46
|
if sort_order.present? && ['asc', 'desc'].include?(sort_order.downcase)
|
|
43
47
|
sort_order.downcase
|
|
@@ -46,6 +50,10 @@ module Katello
|
|
|
46
50
|
end
|
|
47
51
|
end
|
|
48
52
|
|
|
53
|
+
def sanitize_sort_column(sort_column)
|
|
54
|
+
SORTABLE_COLUMNS.include?(sort_column) ? sort_column : 'bootc_booted_image'
|
|
55
|
+
end
|
|
56
|
+
|
|
49
57
|
def index_relation
|
|
50
58
|
query = resource_class.authorized(:view_hosts).distinct
|
|
51
59
|
query.joins(:content_facet).where.not(bootc_booted_image: nil, bootc_booted_digest: nil)
|
|
@@ -34,15 +34,16 @@ module Katello
|
|
|
34
34
|
:ssl_ca_cert,
|
|
35
35
|
:custom_cdn)
|
|
36
36
|
|
|
37
|
+
@cert_store = OpenSSL::X509::Store.new
|
|
37
38
|
if options[:ssl_ca_cert].present?
|
|
38
|
-
@cert_store = OpenSSL::X509::Store.new
|
|
39
39
|
Foreman::Util.add_ca_bundle_to_store(options[:ssl_ca_cert], @cert_store)
|
|
40
40
|
elsif options[:ssl_ca_file]
|
|
41
|
-
@cert_store = OpenSSL::X509::Store.new
|
|
42
41
|
@cert_store.add_file(options[:ssl_ca_file])
|
|
42
|
+
else
|
|
43
|
+
@cert_store.set_default_paths
|
|
43
44
|
end
|
|
44
45
|
|
|
45
|
-
if
|
|
46
|
+
if proxy&.cacert&.present?
|
|
46
47
|
Foreman::Util.add_ca_bundle_to_store(proxy.cacert, @cert_store)
|
|
47
48
|
end
|
|
48
49
|
|
|
@@ -59,8 +60,12 @@ module Katello
|
|
|
59
60
|
options[:ssl_ca_file] = self.ca_file
|
|
60
61
|
self.new(cdn_configuration.url, options)
|
|
61
62
|
elsif cdn_configuration.custom_cdn?
|
|
62
|
-
|
|
63
|
-
|
|
63
|
+
if cdn_configuration.ssl_ca.present?
|
|
64
|
+
options[:ssl_ca_cert] = cdn_configuration.ssl_ca
|
|
65
|
+
elsif cdn_configuration.redhat_cdn_host?
|
|
66
|
+
options[:ssl_ca_file] = self.ca_file
|
|
67
|
+
end
|
|
68
|
+
if cdn_configuration.custom_cdn_auth_enabled? || cdn_configuration.redhat_cdn_host?
|
|
64
69
|
options[:ssl_client_cert] = OpenSSL::X509::Certificate.new(product.certificate)
|
|
65
70
|
options[:ssl_client_key] = OpenSSL::PKey::RSA.new(product.key)
|
|
66
71
|
end
|
|
@@ -41,8 +41,10 @@ module Katello
|
|
|
41
41
|
custom_cdn_auth_enabled
|
|
42
42
|
end
|
|
43
43
|
|
|
44
|
-
def
|
|
45
|
-
|
|
44
|
+
def redhat_cdn_host?
|
|
45
|
+
URI.parse(url).host&.end_with?('.redhat.com')
|
|
46
|
+
rescue URI::InvalidURIError
|
|
47
|
+
false
|
|
46
48
|
end
|
|
47
49
|
|
|
48
50
|
def export_sync?
|
|
@@ -194,6 +194,19 @@ module Katello
|
|
|
194
194
|
content_view_environments.first.default_environment?
|
|
195
195
|
end
|
|
196
196
|
|
|
197
|
+
def content_view_environments_all_default_or_rolling?
|
|
198
|
+
return if content_view_environments.blank?
|
|
199
|
+
# Returns true if all applicable errata are installable, meaning:
|
|
200
|
+
# - First CVEnv is Library (Default Org View + Library environment), OR
|
|
201
|
+
# - All CVEnvs are rolling CVs or Library hosts
|
|
202
|
+
# This determines whether the Applicable/Installable toggle should be hidden.
|
|
203
|
+
return true if content_view_environments.first.default_environment?
|
|
204
|
+
|
|
205
|
+
content_view_environments.all? do |cve|
|
|
206
|
+
cve.content_view&.rolling? || cve.default_environment?
|
|
207
|
+
end
|
|
208
|
+
end
|
|
209
|
+
|
|
197
210
|
def update_repositories_by_paths(paths)
|
|
198
211
|
prefixes = %w(/pulp/deb/ /pulp/repos/ /pulp/content/)
|
|
199
212
|
relative_paths = []
|
|
@@ -337,9 +350,10 @@ module Katello
|
|
|
337
350
|
facet = host.content_facet || host.build_content_facet
|
|
338
351
|
attrs_to_add = {}
|
|
339
352
|
BOOTC_FIELD_FACT_NAMES.each do |fact_name|
|
|
353
|
+
next unless parser.facts.key?(fact_name)
|
|
340
354
|
fact_value = parser.facts[fact_name]
|
|
341
355
|
field_name = fact_name.tr(".", "_")
|
|
342
|
-
attrs_to_add[field_name] = fact_value
|
|
356
|
+
attrs_to_add[field_name] = fact_value
|
|
343
357
|
end
|
|
344
358
|
if attrs_to_add['bootc_booted_digest'].present?
|
|
345
359
|
manifest_entity = find_manifest_entity(digest: attrs_to_add['bootc_booted_digest'])
|
|
@@ -17,7 +17,7 @@ module Katello
|
|
|
17
17
|
# If there are any 'AppStream' variants, we need to make them
|
|
18
18
|
# available to Anaconda
|
|
19
19
|
def additional_media
|
|
20
|
-
appstream_repos = entity.operatingsystem.variant_repos
|
|
20
|
+
appstream_repos = entity.operatingsystem.try(:variant_repos, entity, 'AppStream') || []
|
|
21
21
|
super + (appstream_repos.present? ? appstream_repos : [])
|
|
22
22
|
end
|
|
23
23
|
|
|
@@ -509,8 +509,12 @@ module Katello
|
|
|
509
509
|
}
|
|
510
510
|
elsif root.redhat? && root.cdn_configuration.custom_cdn?
|
|
511
511
|
options = {
|
|
512
|
-
ca_cert:
|
|
512
|
+
ca_cert: custom_cdn_ca_cert,
|
|
513
513
|
}
|
|
514
|
+
if root.cdn_configuration.redhat_cdn_host?
|
|
515
|
+
options[:client_cert] = root.product.certificate
|
|
516
|
+
options[:client_key] = root.product.key
|
|
517
|
+
end
|
|
514
518
|
elsif root.redhat? && root.cdn_configuration.network_sync?
|
|
515
519
|
options = {
|
|
516
520
|
client_cert: root.cdn_configuration.ssl_cert,
|
|
@@ -524,13 +528,18 @@ module Katello
|
|
|
524
528
|
ca_cert: root.ssl_ca_cert&.content,
|
|
525
529
|
}
|
|
526
530
|
end
|
|
527
|
-
append_proxy_cacert(options) if options.key?(:
|
|
531
|
+
append_proxy_cacert(options) if options.key?(:ca_cert)
|
|
528
532
|
options
|
|
529
533
|
end
|
|
530
534
|
|
|
535
|
+
def custom_cdn_ca_cert
|
|
536
|
+
return root.cdn_configuration.ssl_ca if root.cdn_configuration.ssl_ca.present?
|
|
537
|
+
::File.read(::Katello::Resources::CDN::CdnResource.ca_file) if root.cdn_configuration.redhat_cdn_host?
|
|
538
|
+
end
|
|
539
|
+
|
|
531
540
|
def append_proxy_cacert(options)
|
|
532
|
-
if root.http_proxy&.cacert&.present? && options.key?(:
|
|
533
|
-
options[:
|
|
541
|
+
if root.http_proxy&.cacert&.present? && options.key?(:ca_cert)
|
|
542
|
+
options[:ca_cert] = [options[:ca_cert], root.http_proxy.cacert].compact.join("\n")
|
|
534
543
|
end
|
|
535
544
|
options
|
|
536
545
|
end
|
|
@@ -114,8 +114,8 @@ end
|
|
|
114
114
|
|
|
115
115
|
node :permissions do |content_credential|
|
|
116
116
|
{
|
|
117
|
-
:
|
|
118
|
-
:
|
|
119
|
-
:
|
|
117
|
+
:view_content_credentials => content_credential.readable?,
|
|
118
|
+
:edit_content_credentials => content_credential.editable?,
|
|
119
|
+
:destroy_content_credentials => content_credential.deletable?,
|
|
120
120
|
}
|
|
121
121
|
end
|
|
@@ -44,6 +44,10 @@ node :multi_content_view_environment do |content_facet|
|
|
|
44
44
|
content_facet.multi_content_view_environment?
|
|
45
45
|
end
|
|
46
46
|
|
|
47
|
+
node :content_view_environments_all_default_or_rolling do |content_facet|
|
|
48
|
+
content_facet.content_view_environments_all_default_or_rolling?
|
|
49
|
+
end
|
|
50
|
+
|
|
47
51
|
node :allow_multiple_content_views do
|
|
48
52
|
Setting['allow_multiple_content_views']
|
|
49
53
|
end
|
|
@@ -34,6 +34,7 @@
|
|
|
34
34
|
});
|
|
35
35
|
angular.module('Bastion.auth').value('Permissions', angular.fromJson(`<%= User.current.cached_roles.collect { |role| role.permissions }.flatten.to_json.html_safe %>`));
|
|
36
36
|
angular.module('Bastion').value('newHostDetailsUI', "<%= Setting[:host_details_ui] %>");
|
|
37
|
+
angular.module('Bastion').value('newHostsPage', "<%= Setting[:new_hosts_page] %>");
|
|
37
38
|
angular.module('Bastion').value('experimentalLabsSetting', "<%= Setting[:lab_features] %>");
|
|
38
39
|
</script>
|
|
39
40
|
|
|
@@ -17,13 +17,14 @@
|
|
|
17
17
|
* @requires BastionConfig
|
|
18
18
|
* @requires hostIds
|
|
19
19
|
* @requires newHostDetailsUI
|
|
20
|
+
* @requires newHostsPage
|
|
20
21
|
*
|
|
21
22
|
* @description
|
|
22
23
|
* A controller for providing bulk action functionality to the content hosts page.
|
|
23
24
|
*/
|
|
24
25
|
angular.module('Bastion.content-hosts').controller('ContentHostsBulkErrataModalController',
|
|
25
|
-
['$scope', '$http', '$location', '$window', '$timeout', '$uibModalInstance', 'HostBulkAction', 'HostCollection', 'Nutupane', 'CurrentOrganization', 'Erratum', 'Notification', 'BastionConfig', 'hostIds', 'newHostDetailsUI',
|
|
26
|
-
function ($scope, $http, $location, $window, $timeout, $uibModalInstance, HostBulkAction, HostCollection, Nutupane, CurrentOrganization, Erratum, Notification, BastionConfig, hostIds, newHostDetailsUI) {
|
|
26
|
+
['$scope', '$http', '$location', '$window', '$timeout', '$uibModalInstance', 'HostBulkAction', 'HostCollection', 'Nutupane', 'CurrentOrganization', 'Erratum', 'Notification', 'BastionConfig', 'hostIds', 'newHostDetailsUI', 'newHostsPage',
|
|
27
|
+
function ($scope, $http, $location, $window, $timeout, $uibModalInstance, HostBulkAction, HostCollection, Nutupane, CurrentOrganization, Erratum, Notification, BastionConfig, hostIds, newHostDetailsUI, newHostsPage) {
|
|
27
28
|
function fetchErratum(errataId) {
|
|
28
29
|
$scope.erratum = Erratum.get({id: errataId, 'organization_id': CurrentOrganization});
|
|
29
30
|
}
|
|
@@ -43,6 +44,12 @@ angular.module('Bastion.content-hosts').controller('ContentHostsBulkErrataModalC
|
|
|
43
44
|
$scope.allHostsSelected = hostIds.allResultsSelected;
|
|
44
45
|
$scope.hostToolingEnabled = BastionConfig.hostToolingEnabled;
|
|
45
46
|
$scope.newHostDetailsUI = newHostDetailsUI;
|
|
47
|
+
$scope.newHostsPage = (newHostsPage === 'true');
|
|
48
|
+
|
|
49
|
+
$scope.hostsUrl = function(errataId) {
|
|
50
|
+
var basePath = $scope.newHostsPage ? '/new/hosts' : '/hosts';
|
|
51
|
+
return basePath + '?search=installable_errata%3D' + errataId;
|
|
52
|
+
};
|
|
46
53
|
|
|
47
54
|
$scope.errataActionFormValues = {
|
|
48
55
|
authenticityToken: $window.AUTH_TOKEN.replace(/"/g, '')
|
|
@@ -100,7 +100,7 @@
|
|
|
100
100
|
<td class="small" bst-table-cell>{{ erratum.issued }}</td>
|
|
101
101
|
<td class="small" bst-table-cell class="number-cell">
|
|
102
102
|
<span ng-switch="newHostDetailsUI">
|
|
103
|
-
<a ng-switch-when="true" target="_blank" href="{{
|
|
103
|
+
<a ng-switch-when="true" target="_blank" href="{{ hostsUrl(erratum.errata_id) }}">
|
|
104
104
|
{{ erratum.affected_hosts_count }}
|
|
105
105
|
<span class="fa fa-external-link"></span>
|
|
106
106
|
</a>
|
data/engines/bastion_katello/app/assets/javascripts/bastion_katello/debs/details/deb.controller.js
CHANGED
|
@@ -7,11 +7,12 @@
|
|
|
7
7
|
* @requires Host
|
|
8
8
|
* @requires CurrentOrganization
|
|
9
9
|
* @requires newHostDetailsUI
|
|
10
|
+
* @requires newHostsPage
|
|
10
11
|
*
|
|
11
12
|
* @description
|
|
12
13
|
* Provides the functionality for the debs details action pane.
|
|
13
14
|
*/
|
|
14
|
-
function DebController($scope, Deb, Host, CurrentOrganization, ApiErrorHandler, newHostDetailsUI) {
|
|
15
|
+
function DebController($scope, Deb, Host, CurrentOrganization, ApiErrorHandler, newHostDetailsUI, newHostsPage) {
|
|
15
16
|
$scope.panel = {
|
|
16
17
|
error: false,
|
|
17
18
|
loading: true
|
|
@@ -23,6 +24,12 @@
|
|
|
23
24
|
|
|
24
25
|
$scope.installedPackageCount = undefined;
|
|
25
26
|
$scope.newHostDetailsUI = (newHostDetailsUI === 'true');
|
|
27
|
+
$scope.newHostsPage = (newHostsPage === 'true');
|
|
28
|
+
|
|
29
|
+
$scope.newHostUrl = function(field) {
|
|
30
|
+
var basePath = $scope.newHostsPage ? '/new/hosts' : '/hosts';
|
|
31
|
+
return basePath + '?search=' + $scope.createSearchString(field);
|
|
32
|
+
};
|
|
26
33
|
|
|
27
34
|
$scope.fetchHostCount = function() {
|
|
28
35
|
Host.get({'per_page': 0, 'search': $scope.createRawSearchString('installed_deb'), 'organization_id': CurrentOrganization}, function (data) {
|
|
@@ -51,6 +58,6 @@
|
|
|
51
58
|
.module('Bastion.debs')
|
|
52
59
|
.controller('DebController', DebController);
|
|
53
60
|
|
|
54
|
-
DebController.$inject = ['$scope', 'Deb', 'Host', 'CurrentOrganization', 'ApiErrorHandler', 'newHostDetailsUI'];
|
|
61
|
+
DebController.$inject = ['$scope', 'Deb', 'Host', 'CurrentOrganization', 'ApiErrorHandler', 'newHostDetailsUI', 'newHostsPage'];
|
|
55
62
|
|
|
56
63
|
})();
|
data/engines/bastion_katello/app/assets/javascripts/bastion_katello/debs/details/views/deb-info.html
CHANGED
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
<dd>
|
|
10
10
|
<i class="fa fa-spinner fa-spin" ng-show="installedDebCount === undefined"></i>
|
|
11
11
|
<span ng-show="installedDebCount !== undefined">
|
|
12
|
-
<a ng-if="newHostDetailsUI" href="{{
|
|
12
|
+
<a ng-if="newHostDetailsUI" href="{{ newHostUrl('installed_deb') }}" target="_blank" rel="noreferrer noopener" translate>
|
|
13
13
|
{{ installedDebCount }} Host(s)
|
|
14
14
|
</a>
|
|
15
15
|
<a ng-if="!newHostDetailsUI" href="{{ '/content_hosts?search=' + createSearchString('installed_deb') }}" target="_blank" rel="noreferrer noopener" translate>
|
|
@@ -20,7 +20,7 @@
|
|
|
20
20
|
|
|
21
21
|
<dt translate>Applicable To</dt>
|
|
22
22
|
<dd>
|
|
23
|
-
<a ng-if="newHostDetailsUI" href="{{
|
|
23
|
+
<a ng-if="newHostDetailsUI" href="{{ newHostUrl('applicable_debs') }}" target="_blank" rel="noreferrer noopener" translate>
|
|
24
24
|
{{ deb.hosts_applicable_count }} Host(s)
|
|
25
25
|
</a>
|
|
26
26
|
<a ng-if="!newHostDetailsUI" href="{{ '/content_hosts?search=' + createSearchString('applicable_debs') }}" target="_blank" rel="noreferrer noopener" translate>
|
|
@@ -30,7 +30,7 @@
|
|
|
30
30
|
|
|
31
31
|
<dt translate>Upgradable For</dt>
|
|
32
32
|
<dd>
|
|
33
|
-
<a ng-if="newHostDetailsUI" href="{{
|
|
33
|
+
<a ng-if="newHostDetailsUI" href="{{ newHostUrl('upgradable_debs') }}" target="_blank" rel="noreferrer noopener" translate>
|
|
34
34
|
{{ deb.hosts_available_count }} Host(s)
|
|
35
35
|
</a>
|
|
36
36
|
<a ng-if="!newHostDetailsUI" href="{{ '/content_hosts?search=' + createSearchString('upgradable_debs') }}" target="_blank" rel="noreferrer noopener" translate>
|
|
@@ -8,13 +8,14 @@
|
|
|
8
8
|
* @requires CurrentOrganization
|
|
9
9
|
* @requires ApiErrorHandler
|
|
10
10
|
* @requires newHostDetailsUI
|
|
11
|
+
* @requires newHostsPage
|
|
11
12
|
*
|
|
12
13
|
* @description
|
|
13
14
|
* Provides the functionality for the package page.
|
|
14
15
|
*/
|
|
15
16
|
angular.module('Bastion.packages').controller('PackageController',
|
|
16
|
-
['$scope', 'Package', 'Host', 'CurrentOrganization', 'ApiErrorHandler', 'newHostDetailsUI', '
|
|
17
|
-
function ($scope, Package, Host, CurrentOrganization, ApiErrorHandler, newHostDetailsUI) {
|
|
17
|
+
['$scope', 'Package', 'Host', 'CurrentOrganization', 'ApiErrorHandler', 'newHostDetailsUI', 'newHostsPage',
|
|
18
|
+
function ($scope, Package, Host, CurrentOrganization, ApiErrorHandler, newHostDetailsUI, newHostsPage) {
|
|
18
19
|
$scope.panel = {
|
|
19
20
|
error: false,
|
|
20
21
|
loading: true
|
|
@@ -26,6 +27,7 @@ angular.module('Bastion.packages').controller('PackageController',
|
|
|
26
27
|
|
|
27
28
|
$scope.installedPackageCount = undefined;
|
|
28
29
|
$scope.newHostDetailsUI = (newHostDetailsUI === 'true');
|
|
30
|
+
$scope.newHostsPage = (newHostsPage === 'true');
|
|
29
31
|
|
|
30
32
|
$scope.fetchHostCount = function() {
|
|
31
33
|
Host.get({'per_page': 0, 'search': $scope.createSearchString('installed_package'), 'organization_id': CurrentOrganization}, function (data) {
|
|
@@ -43,7 +45,8 @@ angular.module('Bastion.packages').controller('PackageController',
|
|
|
43
45
|
};
|
|
44
46
|
|
|
45
47
|
$scope.newHostUrl = function(field) {
|
|
46
|
-
|
|
48
|
+
var basePath = $scope.newHostsPage ? '/new/hosts' : '/hosts';
|
|
49
|
+
return basePath + '?search=' + encodeURIComponent($scope.createSearchString(field));
|
|
47
50
|
};
|
|
48
51
|
|
|
49
52
|
$scope.package = Package.get({id: $scope.$stateParams.packageId}, function () {
|
data/lib/katello/version.rb
CHANGED
data/locale/action_names.rb
CHANGED
|
@@ -2,7 +2,6 @@
|
|
|
2
2
|
_("Abstract async task")
|
|
3
3
|
_("Add rolling repo clone")
|
|
4
4
|
_("Bulk generate applicability for hosts")
|
|
5
|
-
_("Clean Backend Objects")
|
|
6
5
|
_("Commit upload")
|
|
7
6
|
_("Copy all units")
|
|
8
7
|
_("Copy content")
|
|
@@ -13,7 +12,6 @@ _("Create Container Push Repository Root")
|
|
|
13
12
|
_("Create Export History")
|
|
14
13
|
_("Create Import History")
|
|
15
14
|
_("Create Syncable Export History")
|
|
16
|
-
_("Create content view")
|
|
17
15
|
_("Create exporter")
|
|
18
16
|
_("Create import")
|
|
19
17
|
_("Create importer")
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
@@ -403,11 +403,11 @@ export const ErrataTab = () => {
|
|
|
403
403
|
</>
|
|
404
404
|
) : null;
|
|
405
405
|
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
406
|
+
// Show the Applicable/Installable toggle when not all errata are installable.
|
|
407
|
+
// contentViewEnvironmentsAllDefaultOrRolling is true when all CVEnvs are Library or rolling,
|
|
408
|
+
// meaning all applicable errata are installable and the toggle is unnecessary.
|
|
409
|
+
const showApplicableInstallableToggle =
|
|
410
|
+
contentFacet?.contentViewEnvironmentsAllDefaultOrRolling === false;
|
|
411
411
|
const toggleGroup = (
|
|
412
412
|
<Split hasGutter>
|
|
413
413
|
<SplitItem>
|
|
@@ -432,7 +432,7 @@ export const ErrataTab = () => {
|
|
|
432
432
|
isDisabled={!results?.length}
|
|
433
433
|
/>
|
|
434
434
|
</SplitItem>
|
|
435
|
-
{
|
|
435
|
+
{showApplicableInstallableToggle &&
|
|
436
436
|
<SplitItem>
|
|
437
437
|
<ToggleGroup aria-label="Installable Errata">
|
|
438
438
|
<ToggleGroupItem
|
|
@@ -510,7 +510,7 @@ export const ErrataTab = () => {
|
|
|
510
510
|
displaySelectAllCheckbox={showActions}
|
|
511
511
|
requestKey={HOST_ERRATA_KEY}
|
|
512
512
|
alwaysShowActionButtons={false}
|
|
513
|
-
alwaysShowToggleGroup={
|
|
513
|
+
alwaysShowToggleGroup={showApplicableInstallableToggle && neededErrata}
|
|
514
514
|
>
|
|
515
515
|
<Thead>
|
|
516
516
|
<Tr ouiaId="row-header">
|
|
@@ -19,11 +19,7 @@ jest.mock('../../hostDetailsHelpers', () => ({
|
|
|
19
19
|
const contentFacetAttributes = {
|
|
20
20
|
id: 11,
|
|
21
21
|
uuid: 'e5761ea3-4117-4ecf-83d0-b694f99b389e',
|
|
22
|
-
|
|
23
|
-
contentView: {
|
|
24
|
-
rolling: false,
|
|
25
|
-
},
|
|
26
|
-
lifecycle_environment_library: false,
|
|
22
|
+
content_view_environments_all_default_or_rolling: false,
|
|
27
23
|
errata_counts: {
|
|
28
24
|
total: 3,
|
|
29
25
|
},
|
|
@@ -572,139 +568,45 @@ test('Select all is disabled if all rows are selected', async (done) => {
|
|
|
572
568
|
done(); // Pass jest callback to confirm test is done
|
|
573
569
|
});
|
|
574
570
|
|
|
575
|
-
test('Toggle Group shows
|
|
576
|
-
// Setup autocomplete with mockForemanAutoComplete since we aren't adding /katello
|
|
577
|
-
const autocompleteScope = mockForemanAutocomplete(nockInstance, autocompleteUrl);
|
|
578
|
-
const mockErrata = makeMockErrata({});
|
|
579
|
-
// return errata data results when we look for errata
|
|
580
|
-
const scope = nockInstance
|
|
581
|
-
.get(hostErrata)
|
|
582
|
-
.query(defaultQuery)
|
|
583
|
-
.reply(200, mockErrata);
|
|
584
|
-
|
|
585
|
-
const {
|
|
586
|
-
queryByLabelText,
|
|
587
|
-
getAllByText,
|
|
588
|
-
} = renderWithRedux(<ErrataTab />, renderOptions(cfWithErrataTotal(mockErrata.total)));
|
|
589
|
-
|
|
590
|
-
// Assert that the errata are now showing on the screen, but wait for them to appear.
|
|
591
|
-
await patientlyWaitFor(() => expect(getAllByText('Important')[0]).toBeInTheDocument());
|
|
592
|
-
expect(queryByLabelText('Installable Errata')).toBeInTheDocument();
|
|
593
|
-
assertNockRequest(autocompleteScope);
|
|
594
|
-
assertNockRequest(scope);
|
|
595
|
-
done(); // Pass jest callback to confirm test is done
|
|
596
|
-
});
|
|
597
|
-
|
|
598
|
-
test('Toggle Group shows if it\'s the default content view but non-library environment', async (done) => {
|
|
599
|
-
// Setup autocomplete with mockForemanAutoComplete since we aren't adding /katello
|
|
571
|
+
test('Toggle Group shows when content_view_environments_all_default_or_rolling is false', async (done) => {
|
|
600
572
|
const autocompleteScope = mockForemanAutocomplete(nockInstance, autocompleteUrl);
|
|
601
573
|
const mockErrata = makeMockErrata({});
|
|
602
574
|
const options = renderOptions({
|
|
603
575
|
...cfWithErrataTotal(mockErrata.total),
|
|
604
|
-
|
|
576
|
+
content_view_environments_all_default_or_rolling: false,
|
|
605
577
|
});
|
|
606
|
-
// return errata data results when we look for errata
|
|
607
578
|
const scope = nockInstance
|
|
608
579
|
.get(hostErrata)
|
|
609
580
|
.query(defaultQuery)
|
|
610
581
|
.reply(200, mockErrata);
|
|
611
582
|
|
|
612
|
-
const {
|
|
613
|
-
queryByLabelText,
|
|
614
|
-
getAllByText,
|
|
615
|
-
} = renderWithRedux(<ErrataTab />, options);
|
|
583
|
+
const { queryByLabelText, getAllByText } = renderWithRedux(<ErrataTab />, options);
|
|
616
584
|
|
|
617
|
-
// Assert that the errata are now showing on the screen, but wait for them to appear.
|
|
618
585
|
await patientlyWaitFor(() => expect(getAllByText('Important')[0]).toBeInTheDocument());
|
|
619
586
|
expect(queryByLabelText('Installable Errata')).toBeInTheDocument();
|
|
620
587
|
assertNockRequest(autocompleteScope);
|
|
621
588
|
assertNockRequest(scope);
|
|
622
|
-
done();
|
|
623
|
-
});
|
|
624
|
-
|
|
625
|
-
test('Toggle Group shows if it\'s the library environment but non-default content view', async (done) => {
|
|
626
|
-
// Setup autocomplete with mockForemanAutoComplete since we aren't adding /katello
|
|
627
|
-
const autocompleteScope = mockForemanAutocomplete(nockInstance, autocompleteUrl);
|
|
628
|
-
const mockErrata = makeMockErrata({});
|
|
629
|
-
const options = renderOptions({
|
|
630
|
-
...cfWithErrataTotal(mockErrata.total),
|
|
631
|
-
lifecycle_environment_library: true,
|
|
632
|
-
});
|
|
633
|
-
|
|
634
|
-
// return errata data results when we look for errata
|
|
635
|
-
const scope = nockInstance
|
|
636
|
-
.get(hostErrata)
|
|
637
|
-
.query(defaultQuery)
|
|
638
|
-
.reply(200, mockErrata);
|
|
639
|
-
|
|
640
|
-
const {
|
|
641
|
-
queryByLabelText,
|
|
642
|
-
getAllByText,
|
|
643
|
-
} = renderWithRedux(<ErrataTab />, options);
|
|
644
|
-
|
|
645
|
-
// Assert that the errata are now showing on the screen, but wait for them to appear.
|
|
646
|
-
await patientlyWaitFor(() => expect(getAllByText('Important')[0]).toBeInTheDocument());
|
|
647
|
-
expect(queryByLabelText('Installable Errata')).toBeInTheDocument();
|
|
648
|
-
assertNockRequest(autocompleteScope);
|
|
649
|
-
assertNockRequest(scope);
|
|
650
|
-
done(); // Pass jest callback to confirm test is done
|
|
651
|
-
});
|
|
652
|
-
|
|
653
|
-
test('Toggle Group does not show if it\'s the default content view and library environment', async (done) => {
|
|
654
|
-
// Setup autocomplete with mockForemanAutoComplete since we aren't adding /katello
|
|
655
|
-
const autocompleteScope = mockForemanAutocomplete(nockInstance, autocompleteUrl);
|
|
656
|
-
const mockErrata = makeMockErrata({});
|
|
657
|
-
const options = renderOptions({
|
|
658
|
-
...cfWithErrataTotal(mockErrata.total),
|
|
659
|
-
content_view_default: true,
|
|
660
|
-
lifecycle_environment_library: true,
|
|
661
|
-
});
|
|
662
|
-
// return errata data results when we look for errata
|
|
663
|
-
const scope = nockInstance
|
|
664
|
-
.get(hostErrata)
|
|
665
|
-
.query(defaultQuery)
|
|
666
|
-
.reply(200, mockErrata);
|
|
667
|
-
|
|
668
|
-
const {
|
|
669
|
-
queryByLabelText,
|
|
670
|
-
getAllByText,
|
|
671
|
-
} = renderWithRedux(<ErrataTab />, options);
|
|
672
|
-
|
|
673
|
-
// Assert that the errata are now showing on the screen, but wait for them to appear.
|
|
674
|
-
await patientlyWaitFor(() => expect(getAllByText('Important')[0]).toBeInTheDocument());
|
|
675
|
-
expect(queryByLabelText('Installable Errata')).not.toBeInTheDocument();
|
|
676
|
-
assertNockRequest(autocompleteScope);
|
|
677
|
-
assertNockRequest(scope);
|
|
678
|
-
done(); // Pass jest callback to confirm test is done
|
|
589
|
+
done();
|
|
679
590
|
});
|
|
680
591
|
|
|
681
|
-
test('Toggle Group does not show
|
|
682
|
-
// Setup autocomplete with mockForemanAutoComplete since we aren't adding /katello
|
|
592
|
+
test('Toggle Group does not show when content_view_environments_all_default_or_rolling is true', async (done) => {
|
|
683
593
|
const autocompleteScope = mockForemanAutocomplete(nockInstance, autocompleteUrl);
|
|
684
594
|
const mockErrata = makeMockErrata({});
|
|
685
595
|
const options = renderOptions({
|
|
686
596
|
...cfWithErrataTotal(mockErrata.total),
|
|
687
|
-
|
|
688
|
-
rolling: true,
|
|
689
|
-
},
|
|
690
|
-
lifecycle_environment_library: true,
|
|
597
|
+
content_view_environments_all_default_or_rolling: true,
|
|
691
598
|
});
|
|
692
|
-
// return errata data results when we look for errata
|
|
693
599
|
const scope = nockInstance
|
|
694
600
|
.get(hostErrata)
|
|
695
601
|
.query(defaultQuery)
|
|
696
602
|
.reply(200, mockErrata);
|
|
697
603
|
|
|
698
|
-
const {
|
|
699
|
-
queryByLabelText,
|
|
700
|
-
getAllByText,
|
|
701
|
-
} = renderWithRedux(<ErrataTab />, options);
|
|
604
|
+
const { queryByLabelText, getAllByText } = renderWithRedux(<ErrataTab />, options);
|
|
702
605
|
|
|
703
|
-
// Assert that the errata are now showing on the screen, but wait for them to appear.
|
|
704
606
|
await patientlyWaitFor(() => expect(getAllByText('Important')[0]).toBeInTheDocument());
|
|
705
607
|
expect(queryByLabelText('Installable Errata')).not.toBeInTheDocument();
|
|
706
608
|
assertNockRequest(autocompleteScope);
|
|
707
|
-
assertNockRequest(scope, done);
|
|
609
|
+
assertNockRequest(scope, done);
|
|
708
610
|
});
|
|
709
611
|
|
|
710
612
|
test('Selection is disabled for errata which are applicable but not installable', async (done) => {
|
data/webpack/scenes/AlternateContentSources/Create/__tests__/contentCredentials.fixtures.json
CHANGED
|
@@ -33,9 +33,9 @@
|
|
|
33
33
|
"ssl_key_products": [],
|
|
34
34
|
"ssl_key_root_repos": [],
|
|
35
35
|
"permissions": {
|
|
36
|
-
"
|
|
37
|
-
"
|
|
38
|
-
"
|
|
36
|
+
"view_content_credentials": true,
|
|
37
|
+
"edit_content_credentials": true,
|
|
38
|
+
"destroy_content_credentials": true
|
|
39
39
|
}
|
|
40
40
|
},
|
|
41
41
|
{
|
|
@@ -60,9 +60,9 @@
|
|
|
60
60
|
"ssl_key_products": [],
|
|
61
61
|
"ssl_key_root_repos": [],
|
|
62
62
|
"permissions": {
|
|
63
|
-
"
|
|
64
|
-
"
|
|
65
|
-
"
|
|
63
|
+
"view_content_credentials": true,
|
|
64
|
+
"edit_content_credentials": true,
|
|
65
|
+
"destroy_content_credentials": true
|
|
66
66
|
}
|
|
67
67
|
}
|
|
68
68
|
]
|
|
@@ -104,7 +104,7 @@ const BootedContainerImagesPage = () => {
|
|
|
104
104
|
<TableIndexPage
|
|
105
105
|
apiUrl={BOOTED_CONTAINER_IMAGES_API_PATH}
|
|
106
106
|
apiOptions={apiOptions}
|
|
107
|
-
|
|
107
|
+
creatable={false}
|
|
108
108
|
isDeleteable={false}
|
|
109
109
|
controller="/katello/api/v2/host_bootc_images"
|
|
110
110
|
>
|
|
@@ -35,9 +35,9 @@ const contentCredentialsResponse = Immutable({
|
|
|
35
35
|
ssl_key_products: [],
|
|
36
36
|
ssl_key_root_repos: [],
|
|
37
37
|
permissions: {
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
38
|
+
view_content_credentials: true,
|
|
39
|
+
edit_content_credentials: true,
|
|
40
|
+
destroy_content_credentials: true,
|
|
41
41
|
},
|
|
42
42
|
},
|
|
43
43
|
{
|
|
@@ -62,9 +62,9 @@ const contentCredentialsResponse = Immutable({
|
|
|
62
62
|
ssl_key_products: [],
|
|
63
63
|
ssl_key_root_repos: [],
|
|
64
64
|
permissions: {
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
65
|
+
view_content_credentials: true,
|
|
66
|
+
edit_content_credentials: true,
|
|
67
|
+
destroy_content_credentials: true,
|
|
68
68
|
},
|
|
69
69
|
},
|
|
70
70
|
],
|
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: katello
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 4.20.
|
|
4
|
+
version: 4.20.1
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- N/A
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: bin
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2026-
|
|
11
|
+
date: 2026-05-18 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: rails
|
|
@@ -5624,7 +5624,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
5624
5624
|
- !ruby/object:Gem::Version
|
|
5625
5625
|
version: '0'
|
|
5626
5626
|
requirements: []
|
|
5627
|
-
rubygems_version: 3.
|
|
5627
|
+
rubygems_version: 3.2.33
|
|
5628
5628
|
signing_key:
|
|
5629
5629
|
specification_version: 4
|
|
5630
5630
|
summary: Content and Subscription Management plugin for Foreman
|