katello 4.14.0.rc2 → 4.14.0

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.

Files changed (76) hide show
  1. checksums.yaml +4 -4
  2. data/app/assets/javascripts/katello/common/katello.common.js +1 -1
  3. data/app/assets/javascripts/katello/sync_management/sync_management.js +1 -1
  4. data/app/controllers/katello/api/rhsm/candlepin_proxies_controller.rb +2 -2
  5. data/app/controllers/katello/api/v2/api_controller.rb +2 -2
  6. data/app/controllers/katello/api/v2/host_packages_controller.rb +16 -1
  7. data/app/controllers/katello/api/v2/repositories_bulk_actions_controller.rb +2 -2
  8. data/app/lib/actions/katello/capsule_content/sync.rb +1 -0
  9. data/app/lib/actions/katello/repository/create_root.rb +9 -2
  10. data/app/models/katello/concerns/host_managed_extensions.rb +1 -1
  11. data/app/models/katello/glue/pulp/repos.rb +3 -3
  12. data/app/models/katello/host/info_provider.rb +3 -0
  13. data/app/models/katello/repository.rb +3 -1
  14. data/app/views/katello/api/v2/host_packages/installed_packages.json.rabl +6 -0
  15. data/app/views/katello/sync_management/_controls.html.erb +1 -1
  16. data/config/routes/overrides.rb +1 -0
  17. data/db/migrate/20240729192228_add_convert2rhel_to_host_facets.rb +1 -1
  18. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/content-credentials/new/views/new-content-credential.html +3 -3
  19. data/lib/katello/permission_creator.rb +8 -2
  20. data/lib/katello/version.rb +1 -1
  21. data/locale/bn/LC_MESSAGES/katello.mo +0 -0
  22. data/locale/bn_IN/LC_MESSAGES/katello.mo +0 -0
  23. data/locale/ca/LC_MESSAGES/katello.mo +0 -0
  24. data/locale/cs/LC_MESSAGES/katello.mo +0 -0
  25. data/locale/cs_CZ/LC_MESSAGES/katello.mo +0 -0
  26. data/locale/de/LC_MESSAGES/katello.mo +0 -0
  27. data/locale/de_AT/LC_MESSAGES/katello.mo +0 -0
  28. data/locale/de_DE/LC_MESSAGES/katello.mo +0 -0
  29. data/locale/el/LC_MESSAGES/katello.mo +0 -0
  30. data/locale/en/LC_MESSAGES/katello.mo +0 -0
  31. data/locale/en_GB/LC_MESSAGES/katello.mo +0 -0
  32. data/locale/en_US/LC_MESSAGES/katello.mo +0 -0
  33. data/locale/es/LC_MESSAGES/katello.mo +0 -0
  34. data/locale/et_EE/LC_MESSAGES/katello.mo +0 -0
  35. data/locale/fr/LC_MESSAGES/katello.mo +0 -0
  36. data/locale/gl/LC_MESSAGES/katello.mo +0 -0
  37. data/locale/gu/LC_MESSAGES/katello.mo +0 -0
  38. data/locale/he_IL/LC_MESSAGES/katello.mo +0 -0
  39. data/locale/hi/LC_MESSAGES/katello.mo +0 -0
  40. data/locale/id/LC_MESSAGES/katello.mo +0 -0
  41. data/locale/it/LC_MESSAGES/katello.mo +0 -0
  42. data/locale/ja/LC_MESSAGES/katello.mo +0 -0
  43. data/locale/ka/LC_MESSAGES/katello.mo +0 -0
  44. data/locale/kn/LC_MESSAGES/katello.mo +0 -0
  45. data/locale/ko/LC_MESSAGES/katello.mo +0 -0
  46. data/locale/ml_IN/LC_MESSAGES/katello.mo +0 -0
  47. data/locale/mr/LC_MESSAGES/katello.mo +0 -0
  48. data/locale/nl_NL/LC_MESSAGES/katello.mo +0 -0
  49. data/locale/or/LC_MESSAGES/katello.mo +0 -0
  50. data/locale/pa/LC_MESSAGES/katello.mo +0 -0
  51. data/locale/pl/LC_MESSAGES/katello.mo +0 -0
  52. data/locale/pl_PL/LC_MESSAGES/katello.mo +0 -0
  53. data/locale/pt/LC_MESSAGES/katello.mo +0 -0
  54. data/locale/pt_BR/LC_MESSAGES/katello.mo +0 -0
  55. data/locale/ro/LC_MESSAGES/katello.mo +0 -0
  56. data/locale/ro_RO/LC_MESSAGES/katello.mo +0 -0
  57. data/locale/ru/LC_MESSAGES/katello.mo +0 -0
  58. data/locale/sl/LC_MESSAGES/katello.mo +0 -0
  59. data/locale/sv_SE/LC_MESSAGES/katello.mo +0 -0
  60. data/locale/ta/LC_MESSAGES/katello.mo +0 -0
  61. data/locale/ta_IN/LC_MESSAGES/katello.mo +0 -0
  62. data/locale/te/LC_MESSAGES/katello.mo +0 -0
  63. data/locale/tr/LC_MESSAGES/katello.mo +0 -0
  64. data/locale/vi/LC_MESSAGES/katello.mo +0 -0
  65. data/locale/vi_VN/LC_MESSAGES/katello.mo +0 -0
  66. data/locale/zh/LC_MESSAGES/katello.mo +0 -0
  67. data/locale/zh_CN/LC_MESSAGES/katello.mo +0 -0
  68. data/locale/zh_TW/LC_MESSAGES/katello.mo +0 -0
  69. data/webpack/components/extensions/HostDetails/Tabs/RemoteExecutionActions.js +18 -0
  70. data/webpack/components/extensions/HostDetails/Tabs/RepositorySetsTab/RepositorySetsTab.js +7 -1
  71. data/webpack/components/extensions/HostDetails/Tabs/__tests__/packagesTab.test.js +88 -0
  72. data/webpack/components/extensions/Hosts/BulkActions/BulkErrataWizard/02_BulkErrataTable.js +0 -2
  73. data/webpack/components/extensions/Hosts/BulkActions/BulkPackagesWizard/02_BulkPackagesTable.js +1 -3
  74. data/webpack/components/extensions/Hosts/BulkActions/BulkPackagesWizard/BulkPackagesWizard.js +8 -3
  75. data/webpack/components/extensions/Hosts/BulkActions/HostReview.js +0 -2
  76. metadata +69 -8
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: d82407c5c5f59353d0e535980acdf1e885159503324fdfc3ddb14fee9dbe8369
4
- data.tar.gz: cb93598ca6c89f41ffa97661955c5a16ab7457431ab8ed20fba22e39c4a5f5eb
3
+ metadata.gz: 21ce45d5f478e1cbfce9d978a25ac49d78cb24ae72b60df06d0d040f0a9ad22f
4
+ data.tar.gz: c7051ac4f64ee8815b4df564973146d24254a4af0dbadfc719228ddb1343543b
5
5
  SHA512:
6
- metadata.gz: be8629757389e83723b4db3f6c816473df09f009e73ef34ce6c710e33468c62939710f3bf2392797f146ca45b0d26f2540c2e8696e688ddf8ba7f927d2d2efd2
7
- data.tar.gz: f57e816ce94d26a0f98b3974d6c21936754805177b07f05f076adb953de0c9b21b3453834c9a2e8c1e8eb02539bd1102fc653bdfa8ecc2ab86819eef0ed4ab6c
6
+ metadata.gz: bca7d73c35c724f8f8b19d1b2311f05ea0eb2b1f56ea9c74f9ba61743d85665deca7887ba8f1d218ceb92f08e732a37fb457c9eb16ef5aac2c21e5ed9e1c9fb6
7
+ data.tar.gz: 9f0018048dd7dd5639ce6665e2aff7dfa040407067efc6c484a4eac6e1c960e21902892cdd446d008eab0afccf06bdd50c9d96d0e4367c0a96b5372da6540981
@@ -65,7 +65,7 @@ KT.common = (function() {
65
65
  }
66
66
  },
67
67
  spinner_path : function() {
68
- return "/assets/spinner.gif";
68
+ return document.querySelector('#sync_toggle_cont').dataset.spinnerAssetPath;
69
69
  },
70
70
  to_human_readable_bytes : function(bytes) {
71
71
  var sizes = ['B', 'KB', 'MB', 'GB', 'TB', 'PB'],
@@ -386,7 +386,7 @@ $("#sync_product_form")
386
386
  });
387
387
 
388
388
  $("#sync_toggle").change(function () {
389
- var img = "<img src='" + KT.common.spinner_path() + "'>";
389
+ var img = "<img src='" + KT.common.spinner_path() + "'>";
390
390
  $("#sync_toggle_cont").append(img);
391
391
  if ($(this).is(":checked")) {
392
392
  KT.content.showOnlySyncing();
@@ -332,9 +332,9 @@ module Katello
332
332
  end
333
333
  elsif params.key?(:organization_id) && !params.key?(:environment_id) && !params.key?(:environments)
334
334
  organization = Organization.current
335
- environments = organization.library.content_view_environment
335
+ environments = [organization.library.content_view_environment]
336
336
  elsif User.current.default_organization.present?
337
- environments = User.current.default_organization.library.content_view_environment
337
+ environments = [User.current.default_organization.library.content_view_environment]
338
338
  else
339
339
  fail HttpErrors::NotFound, _("User '%s' did not specify an organization ID and does not have a default organization.") % current_user.login
340
340
  end
@@ -100,8 +100,8 @@ module Katello
100
100
  else
101
101
  query = query.paginate(paginate_options)
102
102
  end
103
- page = params[:page] || 1
104
- per_page = params[:per_page] || Setting[:entries_per_page]
103
+ page = metadata_page # from Foreman Api::V2::BaseController
104
+ per_page = metadata_per_page
105
105
  query = (total.zero? || subtotal.zero?) ? blank_query : query
106
106
 
107
107
  if options[:csv]
@@ -1,6 +1,7 @@
1
1
  module Katello
2
2
  class Api::V2::HostPackagesController < Api::V2::ApiController
3
3
  include Katello::Concerns::FilteredAutoCompleteSearch
4
+ include Katello::Concerns::Api::V2::RepositoryContentController
4
5
 
5
6
  UPGRADABLE = "upgradable".freeze
6
7
  UP_TO_DATE = "up-to-date".freeze
@@ -8,7 +9,7 @@ module Katello
8
9
 
9
10
  before_action :require_packages_or_groups, :only => [:install, :remove]
10
11
  before_action :require_packages_only, :only => [:upgrade]
11
- before_action :find_editable_host_with_facet, :except => :index
12
+ before_action :find_editable_host_with_facet, :except => [:index, :installed_packages]
12
13
  before_action :find_host, :only => :index
13
14
 
14
15
  resource_description do
@@ -21,6 +22,20 @@ module Katello
21
22
  param :groups, Array, :desc => N_("List of package group names (Deprecated)"), :required => false
22
23
  end
23
24
 
25
+ api :GET, "/host_packages/installed_packages", N_("Return a list of installed packages distinct by name")
26
+ param_group :search, ::Katello::Api::V2::ApiController
27
+ def installed_packages
28
+ _sort_by, _sort_order, options = sort_options
29
+ sort_by = 'name'
30
+ sort_order = 'asc'
31
+
32
+ options[:select] = "DISTINCT ON (#{::Katello::InstalledPackage.table_name}.name) #{::Katello::InstalledPackage.table_name}.id, #{::Katello::InstalledPackage.table_name}.name"
33
+ final_relation = ::Katello::InstalledPackage.all
34
+
35
+ result = scoped_search(final_relation, sort_by, sort_order, options)
36
+ respond_for_index(:collection => result, :template => "installed_packages")
37
+ end
38
+
24
39
  api :GET, "/hosts/:host_id/packages", N_("List packages installed on the host")
25
40
  param :host_id, :number, :required => true, :desc => N_("ID of the host")
26
41
  param :include_latest_upgradable, :boolean, :desc => N_("Also include the latest upgradable package version for each host package")
@@ -6,7 +6,7 @@ module Katello
6
6
  param :ids, Array, :desc => N_("List of repository ids"), :required => true
7
7
  def destroy_repositories
8
8
  deletion_authorized_repositories = @repositories.deletable
9
- unpromoted_repos = Setting.find_by(name: 'delete_repo_across_cv')&.value ? deletion_authorized_repositories : deletion_authorized_repositories.reject { |repo| repo.promoted? && repo.content_views.generated_for_none.exists? }
9
+ unpromoted_repos = Setting[:delete_repo_across_cv] ? deletion_authorized_repositories : deletion_authorized_repositories.reject { |repo| repo.promoted? && repo.content_views.generated_for_none.exists? }
10
10
  unpromoted_repos_non_last_affected_repo = unpromoted_repos.reject { |repo| repo.filters.any? { |filter| filter.repositories.size == 1 } }
11
11
  messages1 = format_bulk_action_messages(
12
12
  :success => "",
@@ -36,7 +36,7 @@ module Katello
36
36
  task = async_task(::Actions::BulkAction,
37
37
  ::Actions::Katello::Repository::Destroy,
38
38
  unpromoted_repos_non_last_affected_repo,
39
- remove_from_content_view_versions: Setting.find_by(name: 'delete_repo_across_cv')&.value
39
+ remove_from_content_view_versions: Setting[:delete_repo_across_cv]
40
40
  )
41
41
  else
42
42
  status = 400
@@ -2,6 +2,7 @@ module Actions
2
2
  module Katello
3
3
  module CapsuleContent
4
4
  class Sync < ::Actions::EntryAction
5
+ middleware.do_not_use Dynflow::Middleware::Common::Transaction
5
6
  include ::Actions::ObservableAction
6
7
  def resource_locks
7
8
  :link
@@ -3,11 +3,18 @@ module Actions
3
3
  module Repository
4
4
  class CreateRoot < Actions::EntryAction
5
5
  def plan(root, relative_path = nil)
6
- root.save!
6
+ begin
7
+ root.save!
8
+ rescue ActiveRecord::RecordInvalid
9
+ if root.is_container_push
10
+ logger.warn("Skipping repository creation as container push repository already exists: #{root.container_push_name}")
11
+ return
12
+ end
13
+ end
7
14
  repository = ::Katello::Repository.new(:environment => root.organization.library,
8
15
  :content_view_version => root.organization.library.default_content_view_version,
9
16
  :root => root)
10
- repository.container_repository_name = relative_path
17
+ repository.container_repository_name = relative_path if root.docker? && root.is_container_push
11
18
  repository.relative_path = relative_path || repository.custom_repo_path
12
19
  repository.save!
13
20
 
@@ -498,7 +498,7 @@ module Katello
498
498
  end
499
499
 
500
500
  def package_names_for_job_template(action:, search:, versions: nil)
501
- if self.operatingsystem.family == 'Debian'
501
+ if self&.operatingsystem&.family == 'Debian'
502
502
  deb_names_for_job_template(action: action, search: search)
503
503
  else
504
504
  yum_names_for_job_template(action: action, search: search, versions: versions)
@@ -137,10 +137,10 @@ module Katello
137
137
 
138
138
  # Container push may concurrently call root add several times before the db can update.
139
139
  if repo_param[:is_container_push]
140
- RootRepository.create_or_find_by!(repo_param)
141
- else
142
- RootRepository.new(repo_param)
140
+ root = RootRepository.find_by(repo_param)
141
+ return root if root
143
142
  end
143
+ RootRepository.new(repo_param)
144
144
  end
145
145
  end
146
146
  end
@@ -35,8 +35,11 @@ module Katello
35
35
  end
36
36
 
37
37
  def content_view_info(content_view_environment)
38
+ return {} if content_view_environment.blank?
39
+
38
40
  content_view = content_view_environment.content_view
39
41
  return {} if content_view.blank?
42
+
40
43
  {
41
44
  'label' => content_view.try(:label),
42
45
  'latest-version' => content_view.try(:latest_version),
@@ -272,8 +272,10 @@ module Katello
272
272
  self.content_view_version.content_view
273
273
  end
274
274
 
275
+ # Skip setting container name if the repository is not container type or
276
+ # if it's a library instance of a container-push repo, indicating that the container name is set by the user.
275
277
  def skip_container_name?
276
- self.library_instance? && self.root.docker? && self.root.is_container_push
278
+ !self.root.docker? || (self.root.is_container_push && self.library_instance?)
277
279
  end
278
280
 
279
281
  def library_instance?
@@ -0,0 +1,6 @@
1
+ object false
2
+
3
+ extends "katello/api/v2/common/metadata"
4
+ child @collection[:results] => :results do |_results|
5
+ attributes :name, :id
6
+ end
@@ -21,7 +21,7 @@
21
21
  </a>
22
22
  </div>
23
23
  <% end %>
24
- <div id="sync_toggle_cont" class="fl table-action">
24
+ <div id="sync_toggle_cont" class="fl table-action" data-spinner-asset-path="<%= asset_path('spinner.gif') %>">
25
25
  <input id="sync_toggle" type="checkbox"/>
26
26
  <label for="sync_toggle">
27
27
  <%= _('Active only') %>
@@ -80,6 +80,7 @@ Foreman::Application.routes.draw do
80
80
  match '/bulk/module_streams' => 'hosts_bulk_actions#module_streams', :via => :post
81
81
  match '/bulk/change_content_source' => 'hosts_bulk_actions#change_content_source', :via => :put
82
82
  match '/subscriptions/' => 'host_subscriptions#create', :via => :post
83
+ match '/host_packages/installed_packages' => 'host_packages#installed_packages', :via => :get
83
84
  end
84
85
 
85
86
  resources :packages, :only => [:index], :controller => :host_packages do
@@ -4,6 +4,6 @@ class AddConvert2rhelToHostFacets < ActiveRecord::Migration[6.1]
4
4
  end
5
5
 
6
6
  def down
7
- remove_column :subscription_facets, :convert2rhel_through_foreman
7
+ remove_column :katello_subscription_facets, :convert2rhel_through_foreman
8
8
  end
9
9
  end
@@ -9,7 +9,7 @@
9
9
  ng-upload="uploadContent(content)"
10
10
  upload-options-enable-rails-csrf>
11
11
 
12
- <div bst-form-group label="{{ 'Name' | translate }}">
12
+ <div bst-form-group label="{{ 'Name *' | translate }}">
13
13
  <input id="name"
14
14
  name="name"
15
15
  ng-model="contentCredential.name"
@@ -28,7 +28,7 @@
28
28
  </select>
29
29
  </div>
30
30
 
31
- <div bst-form-group label="{{ 'Content Credential Contents' | translate }}">
31
+ <div bst-form-group label="{{ 'Content Credential Contents *' | translate }}">
32
32
  <textarea name="content"
33
33
  ng-model="contentCredential.pastedContent"
34
34
  tabindex="1"
@@ -36,7 +36,7 @@
36
36
  style="font-family: monospace"
37
37
  rows="15"
38
38
  placeholder="{{ 'Paste contents of Content Credential' | translate }}"
39
- required>
39
+ >
40
40
  </textarea>
41
41
  </div>
42
42
 
@@ -51,6 +51,11 @@ module Katello
51
51
  end
52
52
 
53
53
  def capsule_content_permissions
54
+ @plugin.permission :view_smart_proxies,
55
+ {
56
+ 'katello/api/v2/capsules' => [:index, :show]
57
+ },
58
+ :resource_type => "SmartProxy"
54
59
  @plugin.permission :manage_capsule_content,
55
60
  {
56
61
  'katello/api/v2/capsule_content' => [:add_lifecycle_environment, :remove_lifecycle_environment,
@@ -62,7 +67,7 @@ module Katello
62
67
  @plugin.permission :view_capsule_content,
63
68
  {
64
69
  'katello/api/v2/capsule_content' => [:counts, :lifecycle_environments, :available_lifecycle_environments, :sync_status],
65
- 'smart_proxies' => [:pulp_storage, :pulp_status, :show_with_content],
70
+ 'smart_proxies' => [:pulp_storage, :pulp_status, :show_with_content, :index],
66
71
  'katello/api/v2/capsules' => [:index, :show]
67
72
  },
68
73
  :resource_type => "SmartProxy"
@@ -279,7 +284,8 @@ module Katello
279
284
  :repo_errata,
280
285
  :repo_compare_errata,
281
286
  :repo_compare_packages],
282
- 'katello/api/v2/repository_sets' => [:index, :show, :available_repositories, :auto_complete_search]
287
+ 'katello/api/v2/repository_sets' => [:index, :show, :available_repositories, :auto_complete_search],
288
+ 'katello/api/v2/host_packages' => [:installed_packages]
283
289
  },
284
290
  :resource_type => 'Katello::Product',
285
291
  :finder_scope => :readable
@@ -1,3 +1,3 @@
1
1
  module Katello
2
- VERSION = "4.14.0.rc2".freeze
2
+ VERSION = "4.14.0".freeze
3
3
  end
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
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
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
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
@@ -73,6 +73,14 @@ const katelloPackageRemoveParams = ({ hostname, packageName }) =>
73
73
  feature: REX_FEATURES.KATELLO_PACKAGE_REMOVE,
74
74
  });
75
75
 
76
+ const katelloPackagesRemoveParams = ({ hostname, search, descriptionFormat }) =>
77
+ baseParams({
78
+ hostname,
79
+ inputs: { [PACKAGES_SEARCH_QUERY]: search },
80
+ feature: REX_FEATURES.KATELLO_PACKAGES_REMOVE_BY_SEARCH,
81
+ descriptionFormat,
82
+ });
83
+
76
84
  const katelloPackageRemoveBySearchParams = ({
77
85
  hostname, hostSearch, search, descriptionFormat,
78
86
  }) =>
@@ -209,6 +217,16 @@ export const removePackage = ({ hostname, packageName }) => post({
209
217
  errorToast,
210
218
  });
211
219
 
220
+ // Used by packages wizard
221
+ export const removePackages = ({ hostname, search, descriptionFormat }) => post({
222
+ type: API_OPERATIONS.POST,
223
+ key: REX_JOB_INVOCATIONS_KEY,
224
+ url: foremanApi.getApiUrl('/job_invocations'),
225
+ params: katelloPackagesRemoveParams({ hostname, search, descriptionFormat }),
226
+ handleSuccess: showRexToast,
227
+ errorToast,
228
+ });
229
+
212
230
  export const removePackagesBySearch = ({
213
231
  hostname, hostSearch, search, descriptionFormat,
214
232
  }) => post({
@@ -188,9 +188,13 @@ const RepositorySetsTab = () => {
188
188
  lifecycleEnvironmentLibrary,
189
189
  contentView,
190
190
  lifecycleEnvironment,
191
+ contentViewEnvironments = [],
191
192
  } = contentFacet;
192
193
  const { name: contentViewName } = contentView ?? {};
193
194
  const { name: lifecycleEnvironmentName } = lifecycleEnvironment ?? {};
195
+ const multiEnvHost = contentViewEnvironments.length > 1;
196
+ const contentViewEnvironmentNames =
197
+ contentViewEnvironments.map(({ candlepin_name: candlepinName }) => candlepinName).join(', ');
194
198
  const nonLibraryHost = contentViewDefault === false ||
195
199
  lifecycleEnvironmentLibrary === false;
196
200
  const [isBulkActionOpen, setIsBulkActionOpen] = useState(false);
@@ -497,7 +501,8 @@ const RepositorySetsTab = () => {
497
501
  </Split>
498
502
  ) : null;
499
503
 
500
- const hostEnvText = 'the "{contentViewName}" content view and "{lifecycleEnvironmentName}" environment';
504
+ const hostEnvText = multiEnvHost ? 'the host\'s content view environments: {contentViewEnvironmentNames}'
505
+ : 'the "{contentViewName}" content view and "{lifecycleEnvironmentName}" lifecycle environment';
501
506
 
502
507
  const alertText = (toggleGroupState === LIMIT_TO_ENVIRONMENT ?
503
508
  `Showing only repositories in ${hostEnvText}.` :
@@ -531,6 +536,7 @@ const RepositorySetsTab = () => {
531
536
  values={{
532
537
  contentViewName,
533
538
  lifecycleEnvironmentName,
539
+ contentViewEnvironmentNames,
534
540
  }}
535
541
  />
536
542
  }
@@ -255,6 +255,94 @@ test('Can upgrade a package via customized remote execution', async (done) => {
255
255
  assertNockRequest(statusScope, done);
256
256
  });
257
257
 
258
+ test('Can remove a package via remote execution', async (done) => {
259
+ const autocompleteScope = mockForemanAutocomplete(nockInstance, autocompleteUrl);
260
+
261
+ const scope = nockInstance
262
+ .get(hostPackages)
263
+ .query(defaultQuery)
264
+ .reply(200, { ...mockPackagesData, results: [firstPackage] });
265
+
266
+ const removeScope = nockInstance
267
+ .post(jobInvocations, {
268
+ job_invocation: {
269
+ inputs: {
270
+ package: firstPackage.name,
271
+ },
272
+ search_query: `name ^ (${hostname})`,
273
+ feature: REX_FEATURES.KATELLO_PACKAGE_REMOVE,
274
+ },
275
+ })
276
+ .reply(201);
277
+
278
+ const {
279
+ getByText,
280
+ getAllByText,
281
+ getByLabelText,
282
+ } = renderWithRedux(<PackagesTab />, renderOptions());
283
+
284
+ await patientlyWaitFor(() => expect(getAllByText(firstPackage.name)[0]).toBeInTheDocument());
285
+
286
+ const kebabDropdown = getByLabelText('Actions');
287
+ kebabDropdown.click();
288
+
289
+ const rexAction = getByText('Remove');
290
+ await patientlyWaitFor(() => expect(rexAction).toBeInTheDocument());
291
+ fireEvent.click(rexAction);
292
+
293
+ assertNockRequest(autocompleteScope);
294
+ assertNockRequest(scope);
295
+ assertNockRequest(removeScope, done);
296
+ });
297
+
298
+ test('Can bulk remove a package via remote execution', async (done) => {
299
+ const autocompleteScope = mockForemanAutocomplete(nockInstance, autocompleteUrl);
300
+
301
+ const scope = nockInstance
302
+ .get(hostPackages)
303
+ .query(defaultQuery)
304
+ .reply(200, mockPackagesData);
305
+
306
+ const removeScope = nockInstance
307
+ .post(jobInvocations, {
308
+ job_invocation: {
309
+ inputs: {
310
+ [PACKAGES_SEARCH_QUERY]: `id ^ (${firstPackage.id},${secondPackage.id})`,
311
+ },
312
+ search_query: `name ^ (${hostname})`,
313
+ feature: REX_FEATURES.KATELLO_PACKAGES_REMOVE_BY_SEARCH,
314
+ description_format: 'Remove package(s) chrony, coreutils',
315
+ },
316
+ })
317
+ .reply(201);
318
+
319
+ const {
320
+ getByText,
321
+ getAllByText,
322
+ getByRole,
323
+ getByLabelText,
324
+ } = renderWithRedux(<PackagesTab />, renderOptions());
325
+
326
+ await patientlyWaitFor(() => expect(getAllByText(firstPackage.name)[0]).toBeInTheDocument());
327
+
328
+ getByRole('checkbox', { name: 'Select row 0' }).click();
329
+ expect(getByLabelText('Select row 0').checked).toEqual(true);
330
+ getByRole('checkbox', { name: 'Select row 1' }).click();
331
+ expect(getByLabelText('Select row 1').checked).toEqual(true);
332
+
333
+ const kebabDropdown = getByRole('button', { name: 'bulk_actions' });
334
+ await patientlyWaitFor(() => expect(kebabDropdown).toBeInTheDocument());
335
+ fireEvent.click(kebabDropdown);
336
+
337
+ const rexAction = getByText('Remove');
338
+ await patientlyWaitFor(() => expect(rexAction).toBeInTheDocument());
339
+ fireEvent.click(rexAction);
340
+
341
+ assertNockRequest(autocompleteScope);
342
+ assertNockRequest(scope);
343
+ assertNockRequest(removeScope, done);
344
+ });
345
+
258
346
  test('Can bulk upgrade via remote execution', async (done) => {
259
347
  const autocompleteScope = mockForemanAutocomplete(nockInstance, autocompleteUrl);
260
348
 
@@ -148,8 +148,6 @@ const BulkErrataTable = () => {
148
148
  showCheckboxes
149
149
  apiUrl={ERRATA_URL}
150
150
  apiOptions={apiOptions}
151
- headerText={__('Errata')}
152
- header={null}
153
151
  controller="errata"
154
152
  customSearchProps={customSearchProps}
155
153
  creatable={false}
@@ -93,7 +93,7 @@ const BulkPackagesTable = ({
93
93
  name: {
94
94
  title: __('Package'),
95
95
  wrapper: ({ name, id }) => (
96
- <a target="_blank" href={`/packages/${id}`} rel="noreferrer">{name}</a>
96
+ <a target="_blank" href={tableType === 'remove' ? `/packages?search=${name}` : `/packages/${id}`} rel="noreferrer">{name}</a>
97
97
  ),
98
98
  isSorted: true,
99
99
  weight: 50,
@@ -133,8 +133,6 @@ const BulkPackagesTable = ({
133
133
  showCheckboxes
134
134
  apiUrl={PACKAGES_URL}
135
135
  apiOptions={apiOptions}
136
- headerText={__('Packages')}
137
- header={null}
138
136
  controller="packages"
139
137
  customSearchProps={customSearchProps}
140
138
  creatable={false}
@@ -12,7 +12,7 @@ import HostReview from '../HostReview';
12
12
  import { BulkPackagesReview, dropdownOptions } from './04_Review';
13
13
  import { BulkPackagesUpgradeTable, BulkPackagesInstallTable, BulkPackagesRemoveTable } from './02_BulkPackagesTable';
14
14
  import { BulkPackagesReviewFooter } from './04_ReviewFooter';
15
- import katelloApi from '../../../../../services/api';
15
+ import katelloApi, { foremanApi } from '../../../../../services/api';
16
16
 
17
17
  export const UPGRADE_ALL = 'upgradeAll';
18
18
  export const UPGRADE = 'upgrade';
@@ -53,8 +53,13 @@ export const useHostsBulkSelect = ({ initialSelectedHosts, modalIsOpen }) => {
53
53
  };
54
54
  };
55
55
 
56
- export const getPackagesUrl = selectedAction =>
57
- `${katelloApi.getApiUrl('/packages/thindex')}?per_page=7&include_permissions=true&packages_restrict_upgradable=${selectedAction === 'upgrade'}`;
56
+ export const getPackagesUrl = (selectedAction) => {
57
+ if (selectedAction === REMOVE) {
58
+ return `${foremanApi.getApiUrl('/hosts/host_packages/installed_packages')}?per_page=7&include_permissions=true`;
59
+ }
60
+
61
+ return `${katelloApi.getApiUrl('/packages/thindex')}?per_page=7&include_permissions=true&packages_restrict_upgradable=${selectedAction === 'upgrade'}`;
62
+ };
58
63
 
59
64
  const BulkPackagesWizard = () => {
60
65
  const { modalOpen, setModalClosed: closeModal } = useForemanModal({ id: 'bulk-packages-wizard' });
@@ -122,8 +122,6 @@ const HostReview = ({
122
122
  showCheckboxes
123
123
  apiUrl={HOSTS_API_PATH}
124
124
  apiOptions={apiOptions}
125
- headerText={__('Hosts')}
126
- header={null}
127
125
  controller="hosts"
128
126
  creatable={false}
129
127
  replacementResponse={response}
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.14.0.rc2
4
+ version: 4.14.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - N/A
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2024-09-05 00:00:00.000000000 Z
11
+ date: 2024-09-17 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rails
@@ -86,28 +86,40 @@ dependencies:
86
86
  requirements:
87
87
  - - ">="
88
88
  - !ruby/object:Gem::Version
89
- version: '9.1'
89
+ version: 9.2.3
90
+ - - "<"
91
+ - !ruby/object:Gem::Version
92
+ version: '10.0'
90
93
  type: :runtime
91
94
  prerelease: false
92
95
  version_requirements: !ruby/object:Gem::Requirement
93
96
  requirements:
94
97
  - - ">="
95
98
  - !ruby/object:Gem::Version
96
- version: '9.1'
99
+ version: 9.2.3
100
+ - - "<"
101
+ - !ruby/object:Gem::Version
102
+ version: '10.0'
97
103
  - !ruby/object:Gem::Dependency
98
104
  name: foreman_remote_execution
99
105
  requirement: !ruby/object:Gem::Requirement
100
106
  requirements:
101
107
  - - ">="
102
108
  - !ruby/object:Gem::Version
103
- version: 7.1.0
109
+ version: 13.2.5
110
+ - - "<"
111
+ - !ruby/object:Gem::Version
112
+ version: 14.0.0
104
113
  type: :runtime
105
114
  prerelease: false
106
115
  version_requirements: !ruby/object:Gem::Requirement
107
116
  requirements:
108
117
  - - ">="
109
118
  - !ruby/object:Gem::Version
110
- version: 7.1.0
119
+ version: 13.2.5
120
+ - - "<"
121
+ - !ruby/object:Gem::Version
122
+ version: 14.0.0
111
123
  - !ruby/object:Gem::Dependency
112
124
  name: dynflow
113
125
  requirement: !ruby/object:Gem::Requirement
@@ -1567,6 +1579,7 @@ files:
1567
1579
  - app/views/katello/api/v2/host_module_streams/index.json.rabl
1568
1580
  - app/views/katello/api/v2/host_packages/base.json.rabl
1569
1581
  - app/views/katello/api/v2/host_packages/index.json.rabl
1582
+ - app/views/katello/api/v2/host_packages/installed_packages.json.rabl
1570
1583
  - app/views/katello/api/v2/host_subscriptions/available_release_versions.json.rabl
1571
1584
  - app/views/katello/api/v2/host_subscriptions/events.json.rabl
1572
1585
  - app/views/katello/api/v2/host_subscriptions/index.json.rabl
@@ -4374,55 +4387,103 @@ files:
4374
4387
  - locale/Makefile
4375
4388
  - locale/README
4376
4389
  - locale/action_names.rb
4390
+ - locale/bn/LC_MESSAGES/katello.mo
4377
4391
  - locale/bn/katello.po
4392
+ - locale/bn_IN/LC_MESSAGES/katello.mo
4378
4393
  - locale/bn_IN/katello.po
4394
+ - locale/ca/LC_MESSAGES/katello.mo
4379
4395
  - locale/ca/katello.po
4396
+ - locale/cs/LC_MESSAGES/katello.mo
4380
4397
  - locale/cs/katello.po
4398
+ - locale/cs_CZ/LC_MESSAGES/katello.mo
4381
4399
  - locale/cs_CZ/katello.po
4400
+ - locale/de/LC_MESSAGES/katello.mo
4382
4401
  - locale/de/katello.po
4402
+ - locale/de_AT/LC_MESSAGES/katello.mo
4383
4403
  - locale/de_AT/katello.po
4404
+ - locale/de_DE/LC_MESSAGES/katello.mo
4384
4405
  - locale/de_DE/katello.po
4406
+ - locale/el/LC_MESSAGES/katello.mo
4385
4407
  - locale/el/katello.po
4408
+ - locale/en/LC_MESSAGES/katello.mo
4386
4409
  - locale/en/katello.po
4410
+ - locale/en_GB/LC_MESSAGES/katello.mo
4387
4411
  - locale/en_GB/katello.po
4412
+ - locale/en_US/LC_MESSAGES/katello.mo
4388
4413
  - locale/en_US/katello.po
4414
+ - locale/es/LC_MESSAGES/katello.mo
4389
4415
  - locale/es/katello.po
4416
+ - locale/et_EE/LC_MESSAGES/katello.mo
4390
4417
  - locale/et_EE/katello.po
4418
+ - locale/fr/LC_MESSAGES/katello.mo
4391
4419
  - locale/fr/katello.po
4420
+ - locale/gl/LC_MESSAGES/katello.mo
4392
4421
  - locale/gl/katello.po
4422
+ - locale/gu/LC_MESSAGES/katello.mo
4393
4423
  - locale/gu/katello.po
4424
+ - locale/he_IL/LC_MESSAGES/katello.mo
4394
4425
  - locale/he_IL/katello.po
4426
+ - locale/hi/LC_MESSAGES/katello.mo
4395
4427
  - locale/hi/katello.po
4428
+ - locale/id/LC_MESSAGES/katello.mo
4396
4429
  - locale/id/katello.po
4430
+ - locale/it/LC_MESSAGES/katello.mo
4397
4431
  - locale/it/katello.po
4432
+ - locale/ja/LC_MESSAGES/katello.mo
4398
4433
  - locale/ja/katello.po
4434
+ - locale/ka/LC_MESSAGES/katello.mo
4399
4435
  - locale/ka/katello.po
4400
4436
  - locale/katello.pot
4437
+ - locale/kn/LC_MESSAGES/katello.mo
4401
4438
  - locale/kn/katello.po
4439
+ - locale/ko/LC_MESSAGES/katello.mo
4402
4440
  - locale/ko/katello.po
4441
+ - locale/ml_IN/LC_MESSAGES/katello.mo
4403
4442
  - locale/ml_IN/katello.po
4443
+ - locale/mr/LC_MESSAGES/katello.mo
4404
4444
  - locale/mr/katello.po
4445
+ - locale/nl_NL/LC_MESSAGES/katello.mo
4405
4446
  - locale/nl_NL/katello.po
4447
+ - locale/or/LC_MESSAGES/katello.mo
4406
4448
  - locale/or/katello.po
4449
+ - locale/pa/LC_MESSAGES/katello.mo
4407
4450
  - locale/pa/katello.po
4451
+ - locale/pl/LC_MESSAGES/katello.mo
4408
4452
  - locale/pl/katello.po
4453
+ - locale/pl_PL/LC_MESSAGES/katello.mo
4409
4454
  - locale/pl_PL/katello.po
4455
+ - locale/pt/LC_MESSAGES/katello.mo
4410
4456
  - locale/pt/katello.po
4457
+ - locale/pt_BR/LC_MESSAGES/katello.mo
4411
4458
  - locale/pt_BR/katello.po
4459
+ - locale/ro/LC_MESSAGES/katello.mo
4412
4460
  - locale/ro/katello.po
4461
+ - locale/ro_RO/LC_MESSAGES/katello.mo
4413
4462
  - locale/ro_RO/katello.po
4463
+ - locale/ru/LC_MESSAGES/katello.mo
4414
4464
  - locale/ru/katello.po
4465
+ - locale/sl/LC_MESSAGES/katello.mo
4415
4466
  - locale/sl/katello.po
4467
+ - locale/sv_SE/LC_MESSAGES/katello.mo
4416
4468
  - locale/sv_SE/katello.po
4469
+ - locale/ta/LC_MESSAGES/katello.mo
4417
4470
  - locale/ta/katello.po
4471
+ - locale/ta_IN/LC_MESSAGES/katello.mo
4418
4472
  - locale/ta_IN/katello.po
4473
+ - locale/te/LC_MESSAGES/katello.mo
4419
4474
  - locale/te/katello.po
4475
+ - locale/tr/LC_MESSAGES/katello.mo
4420
4476
  - locale/tr/katello.po
4421
4477
  - locale/update-i18n
4478
+ - locale/vi/LC_MESSAGES/katello.mo
4422
4479
  - locale/vi/katello.po
4480
+ - locale/vi_VN/LC_MESSAGES/katello.mo
4423
4481
  - locale/vi_VN/katello.po
4482
+ - locale/zh/LC_MESSAGES/katello.mo
4424
4483
  - locale/zh/katello.po
4484
+ - locale/zh_CN/LC_MESSAGES/katello.mo
4425
4485
  - locale/zh_CN/katello.po
4486
+ - locale/zh_TW/LC_MESSAGES/katello.mo
4426
4487
  - locale/zh_TW/katello.po
4427
4488
  - package.json
4428
4489
  - vendor/assets/images/katello/add2.png
@@ -5390,9 +5451,9 @@ required_ruby_version: !ruby/object:Gem::Requirement
5390
5451
  version: '4'
5391
5452
  required_rubygems_version: !ruby/object:Gem::Requirement
5392
5453
  requirements:
5393
- - - ">"
5454
+ - - ">="
5394
5455
  - !ruby/object:Gem::Version
5395
- version: 1.3.1
5456
+ version: '0'
5396
5457
  requirements: []
5397
5458
  rubygems_version: 3.2.33
5398
5459
  signing_key: