katello 4.4.0 → 4.4.1

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 (34) hide show
  1. checksums.yaml +4 -4
  2. data/app/controllers/katello/api/v2/errata_controller.rb +3 -1
  3. data/app/controllers/katello/api/v2/module_streams_controller.rb +3 -1
  4. data/app/controllers/katello/api/v2/package_groups_controller.rb +3 -1
  5. data/app/lib/actions/katello/repository/filtered_index_content.rb +3 -3
  6. data/app/lib/actions/pulp3/repository/refresh_distribution.rb +1 -4
  7. data/app/lib/actions/pulp3/repository/save_distribution_references.rb +0 -2
  8. data/app/models/katello/concerns/pulp_database_unit.rb +2 -1
  9. data/app/services/katello/content_unit_indexer.rb +3 -3
  10. data/app/services/katello/pulp3/erratum.rb +1 -1
  11. data/app/services/katello/pulp3/repository.rb +29 -1
  12. data/app/views/foreman/smart_proxies/show.html.erb +2 -0
  13. data/app/views/katello/api/v2/module_streams/show.json.rabl +0 -7
  14. data/db/migrate/20220303160220_remove_duplicate_errata.rb +44 -3
  15. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/products/details/repositories/mirroring-policy.service.js +1 -1
  16. data/lib/katello/version.rb +1 -1
  17. data/webpack/components/RoutedTabs/index.js +17 -1
  18. data/webpack/scenes/ContentViews/Create/CreateContentViewForm.js +2 -2
  19. data/webpack/scenes/ContentViews/Create/__tests__/createContentView.test.js +1 -1
  20. data/webpack/scenes/ContentViews/Details/ComponentContentViews/ComponentContentViewAddModal.js +1 -1
  21. data/webpack/scenes/ContentViews/Details/ComponentContentViews/ComponentContentViewBulkAddModal.js +2 -2
  22. data/webpack/scenes/ContentViews/Details/ComponentContentViews/__tests__/contentViewComponents.test.js +4 -4
  23. data/webpack/scenes/ContentViews/Details/ContentViewInfo.js +1 -1
  24. data/webpack/scenes/ContentViews/__tests__/contentViewPage.test.js +4 -4
  25. data/webpack/scenes/ContentViews/components/ContentViewsCounter.js +1 -1
  26. data/webpack/scenes/ContentViews/expansions/DetailsExpansion.js +2 -2
  27. data/webpack/scenes/ContentViews/expansions/RelatedContentViewComponentsModal.js +2 -2
  28. data/webpack/scenes/ContentViews/expansions/__tests__/contentViewComponentsModal.test.js +1 -1
  29. data/webpack/scenes/ModuleStreams/Details/ModuleDetailsSchema.js +1 -10
  30. data/webpack/scenes/ModuleStreams/Details/ModuleStreamDetails.js +13 -14
  31. data/webpack/scenes/ModuleStreams/Details/__tests__/__snapshots__/ModuleStreamDetails.test.js.snap +17 -100
  32. data/webpack/scenes/Subscriptions/Manifest/CdnConfigurationTab/CdnConfigurationConstants.js +1 -0
  33. data/webpack/scenes/Subscriptions/Manifest/CdnConfigurationTab/UpstreamServerTypeForm.js +9 -7
  34. metadata +2 -2
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: e193a2273fbdeccfaeb286b7a86738e7bbb1bb78120a663e4309aac912ef4501
4
- data.tar.gz: afbec4d28494d215e8b7c318cd403a632d3c8c14ccff79f809cc01f4fc713f3d
3
+ metadata.gz: 60531c92a13f5d62aaea839bc1dc5512f0a75b0eea7f7a7820c0144747928501
4
+ data.tar.gz: ec6e2f242dabd880929727846034aae0356aa76ae61a467864f66703b5899093
5
5
  SHA512:
6
- metadata.gz: da5af110e6327f56eff8c5f72eb1e80936142b534e68d9bdc9f081efa9838f35b0eb03d99e461e59f9c0f2be1a55f7955f2fee6d97b8874f35ce4ba60bb4c1df
7
- data.tar.gz: 6c6db26dac3ffa0ace7837e9774d56d93cba08df34fee0616bde18816a6785e5c54d697768d2f5a39bbd40a67b990462bb9e2e7e2d44cfdd74043221ca820dd6
6
+ metadata.gz: 5a678ed0980575f97093e0908c58964ce62137ab502b0c5b2755f04d09466c8ed77e00f7ae120762a6006347d33d7ce7b94bf045c62799023d8efa0912426b44
7
+ data.tar.gz: 7a4e2f5eb5afac20586eb0c1581d560991cd012ded9887a249d873c579384b0d64f34db23d86a31db2d8f941b00a37f2bc579bad7ae6ad778f13e698b03137f5
@@ -35,7 +35,9 @@ module Katello
35
35
  end
36
36
 
37
37
  def all_for_content_view_filter(filter, _collection)
38
- Erratum.joins(:repositories).merge(filter.applicable_repos)
38
+ available_ids = Erratum.joins(:repositories).merge(filter.applicable_repos)&.pluck(:errata_id) || []
39
+ added_ids = filter&.erratum_rules&.pluck(:errata_id) || []
40
+ Erratum.where(errata_id: available_ids + added_ids)
39
41
  end
40
42
 
41
43
  def custom_index_relation(collection)
@@ -36,7 +36,9 @@ module Katello
36
36
  end
37
37
 
38
38
  def all_for_content_view_filter(filter, _collection)
39
- ModuleStream.joins(:repositories).merge(filter.applicable_repos)
39
+ available_ids = ModuleStream.joins(:repositories).merge(filter.applicable_repos)&.pluck(:id) || []
40
+ added_ids = filter&.module_stream_rules&.pluck(:module_stream_id) || []
41
+ ModuleStream.where(id: available_ids + added_ids)
40
42
  end
41
43
 
42
44
  def available_for_content_view_filter(filter, _collection)
@@ -67,7 +67,9 @@ module Katello
67
67
  end
68
68
 
69
69
  def all_for_content_view_filter(filter, _collection)
70
- PackageGroup.joins(:repositories).merge(filter.applicable_repos)
70
+ available_ids = PackageGroup.joins(:repositories).merge(filter.applicable_repos)&.pluck(:pulp_id) || []
71
+ added_ids = filter&.package_group_rules&.pluck(:uuid) || []
72
+ PackageGroup.where(pulp_id: available_ids + added_ids)
71
73
  end
72
74
 
73
75
  def default_sort
@@ -36,7 +36,7 @@ module Actions
36
36
  else
37
37
  unit_ids = search_units(repo)
38
38
  end
39
- ::Katello::Deb.import_all(unit_ids, repo)
39
+ ::Katello::Deb.import_all(unit_ids, repo, {filtered_indexing: true})
40
40
  elsif repo.yum?
41
41
  if input[:import_upload_task] && input[:import_upload_task][:content_unit_href]
42
42
  unit_ids = [input[:import_upload_task][:content_unit_href]]
@@ -48,9 +48,9 @@ module Actions
48
48
  unit_ids = search_units(repo)
49
49
  end
50
50
  if input[:content_type] == ::Katello::Srpm::CONTENT_TYPE
51
- ::Katello::Srpm.import_all(unit_ids, repo)
51
+ ::Katello::Srpm.import_all(unit_ids, repo, {filtered_indexing: true})
52
52
  else
53
- ::Katello::Rpm.import_all(unit_ids, repo)
53
+ ::Katello::Rpm.import_all(unit_ids, repo, {filtered_indexing: true})
54
54
  end
55
55
  end
56
56
  end
@@ -3,7 +3,6 @@ module Actions
3
3
  module Repository
4
4
  class RefreshDistribution < Pulp3::AbstractAsyncTask
5
5
  include Helpers::Presenter
6
- middleware.use Actions::Middleware::ExecuteIfContentsChanged
7
6
 
8
7
  def plan(repository, smart_proxy, options = {})
9
8
  smart_proxy = SmartProxy.unscoped.find_by(id: smart_proxy) #support bulk actions
@@ -16,11 +15,9 @@ module Actions
16
15
  :repository_id => repository.id,
17
16
  :smart_proxy_id => smart_proxy.id
18
17
  }
19
- refresh_options[:contents_changed] if options.key?(:contents_changed)
20
18
  action = plan_self(refresh_options)
21
19
 
22
- plan_action(SaveDistributionReferences, repository, smart_proxy,
23
- action.output, :contents_changed => options[:contents_changed])
20
+ plan_action(SaveDistributionReferences, repository, smart_proxy, action.output)
24
21
  end
25
22
  end
26
23
 
@@ -2,8 +2,6 @@ module Actions
2
2
  module Pulp3
3
3
  module Repository
4
4
  class SaveDistributionReferences < Pulp3::Abstract
5
- middleware.use Actions::Middleware::ExecuteIfContentsChanged
6
-
7
5
  def plan(repository, smart_proxy, tasks, options = {})
8
6
  plan_self(repository_id: repository.id, smart_proxy_id: smart_proxy.id, tasks: tasks, contents_changed: options[:contents_changed])
9
7
  end
@@ -81,7 +81,8 @@ module Katello
81
81
 
82
82
  def import_all(unit_ids, repository = nil, options = {})
83
83
  content_type = options[:content_type] || self.content_type
84
- Katello::ContentUnitIndexer.new(content_type: Katello::RepositoryTypeManager.find_content_type(content_type), repository: repository, pulp_content_ids: unit_ids).import_all
84
+ filtered_indexing = options[:filtered_indexing] || false
85
+ Katello::ContentUnitIndexer.new(content_type: Katello::RepositoryTypeManager.find_content_type(content_type), repository: repository, pulp_content_ids: unit_ids).import_all(filtered_indexing)
85
86
  end
86
87
 
87
88
  def copy_repository_associations(source_repo, dest_repo)
@@ -21,9 +21,9 @@ module Katello
21
21
  end
22
22
  end
23
23
 
24
- def import_all
24
+ def import_all(filtered_indexing = false)
25
+ additive = filtered_indexing || (@repository&.mirroring_policy == 'additive')
25
26
  association_tracker = RepoAssociationTracker.new(@content_type, @service_class, @repository)
26
-
27
27
  units_from_pulp.each do |units|
28
28
  units.each do |unit|
29
29
  association_tracker.push(unit)
@@ -52,7 +52,7 @@ module Katello
52
52
  end
53
53
 
54
54
  if @model_class.many_repository_associations && @repository
55
- sync_repository_associations(association_tracker)
55
+ sync_repository_associations(association_tracker, additive: additive)
56
56
  end
57
57
  end
58
58
 
@@ -119,7 +119,7 @@ module Katello
119
119
  date.to_i.to_s == date ? epoch_to_date(date) : date
120
120
  end
121
121
 
122
- def epoch_to_date(epoch)
122
+ def self.epoch_to_date(epoch)
123
123
  Time.at(epoch.to_i).to_s
124
124
  end
125
125
  end
@@ -285,11 +285,17 @@ module Katello
285
285
  return update_distribution
286
286
  end
287
287
 
288
- if dist_ref
288
+ if dist && dist_ref
289
+ # If the saved distribution reference is wrong, delete it and use the existing distribution
290
+ if dist.pulp_href != dist_ref.href
291
+ dist_ref.destroy
292
+ save_distribution_references([dist.pulp_href])
293
+ end
289
294
  return update_distribution
290
295
  end
291
296
 
292
297
  # Since we got this far, we need to create a new distribution
298
+ # Note: the distribution reference can't be saved yet because distribution creation is async
293
299
  begin
294
300
  create_distribution(relative_path)
295
301
  rescue api.client_module::ApiError => e
@@ -307,6 +313,9 @@ module Katello
307
313
 
308
314
  def create_distribution(path)
309
315
  distribution_data = api.distribution_class.new(secure_distribution_options(path))
316
+ unless ::Katello::RepositoryTypeManager.find(repo.content_type).pulp3_skip_publication
317
+ fail_missing_publication(distribution_data.publication)
318
+ end
310
319
  api.distributions_api.create(distribution_data)
311
320
  end
312
321
 
@@ -314,9 +323,16 @@ module Katello
314
323
  api.distributions_api.list(args).results
315
324
  end
316
325
 
326
+ def read_distribution(href = distribution_reference.href)
327
+ ignore_404_exception { api.distributions_api.read(href) }
328
+ end
329
+
317
330
  def update_distribution
318
331
  if distribution_reference
319
332
  options = secure_distribution_options(relative_path).except(:name)
333
+ unless ::Katello::RepositoryTypeManager.find(repo.content_type).pulp3_skip_publication
334
+ fail_missing_publication(options[:publication])
335
+ end
320
336
  distribution_reference.update(:content_guard_href => options[:content_guard])
321
337
  api.distributions_api.partial_update(distribution_reference.href, options)
322
338
  end
@@ -375,6 +391,12 @@ module Katello
375
391
  hrefs.each do |href|
376
392
  pulp3_distribution_data = api.get_distribution(href)
377
393
  path, content_guard_href = pulp3_distribution_data&.base_path, pulp3_distribution_data&.content_guard
394
+ if distribution_reference
395
+ found_distribution = read_distribution(distribution_reference.href)
396
+ unless found_distribution
397
+ distribution_reference.destroy
398
+ end
399
+ end
378
400
  unless distribution_reference
379
401
  # Ensure that duplicates won't be created in the case of a race condition
380
402
  DistributionReference.where(path: path, href: href, repository_id: repo.id, content_guard_href: content_guard_href).first_or_create!
@@ -529,6 +551,12 @@ module Katello
529
551
  return 0 if root.retain_package_versions_count.nil? || root.using_mirrored_content?
530
552
  root.retain_package_versions_count.to_i
531
553
  end
554
+
555
+ def fail_missing_publication(publication_href)
556
+ unless lookup_publication(publication_href)
557
+ fail _("The repository's publication is missing. Please run a 'complete sync' on %s." % repo.name)
558
+ end
559
+ end
532
560
  end
533
561
  end
534
562
  end
@@ -6,4 +6,6 @@
6
6
  <div ng-controller="PulpPrimaryController">
7
7
  <%= render :file => 'smart_proxies/show' %>
8
8
  </div>
9
+ <% else -%>
10
+ <%= render :file => 'smart_proxies/show' %>
9
11
  <% end -%>
@@ -6,13 +6,6 @@ child :artifacts => :artifacts do
6
6
  attributes :id, :name
7
7
  end
8
8
 
9
- child :profiles => :profiles do
10
- attributes :id, :name
11
- child :rpms => :rpms do
12
- attributes :id, :name
13
- end
14
- end
15
-
16
9
  child :library_repositories => :repositories do
17
10
  attributes :id, :name
18
11
  glue :product do
@@ -1,4 +1,8 @@
1
1
  class RemoveDuplicateErrata < ActiveRecord::Migration[6.0]
2
+ # rubocop:disable Metrics/MethodLength
3
+ # rubocop:disable Metrics/AbcSize
4
+ # rubocop:disable Metrics/CyclomaticComplexity
5
+ # rubocop:disable Metrics/PerceivedComplexity
2
6
  def up
3
7
  #Update all unique errata records to have pulp_id = errata_id
4
8
  ::Katello::Erratum.group(:errata_id).having("count(errata_id) = 1").pluck(:errata_id).each do |original_errata_id|
@@ -12,7 +16,7 @@ class RemoveDuplicateErrata < ActiveRecord::Migration[6.0]
12
16
  #For duplicate errata,
13
17
  # a) update all RepositoryErrata to point to unique errata,
14
18
  # b) if repo-errata association for that combination exists, delete duplicate errata association
15
- # c) Delete all duplicate errata
19
+ # c) Delete all duplicate errata and child records
16
20
  ::Katello::Erratum.group(:errata_id).having("count(errata_id) > 1").pluck(:errata_id).each do |original_errata_id|
17
21
  errata_to_keep = ::Katello::Erratum.find_by(pulp_id: original_errata_id)
18
22
  errata_all = ::Katello::Erratum.where(errata_id: original_errata_id)
@@ -24,11 +28,48 @@ class RemoveDuplicateErrata < ActiveRecord::Migration[6.0]
24
28
  repo_erratum.update(erratum_id: errata_to_keep.id)
25
29
  end
26
30
  end
27
- ::Katello::Erratum.delete(dup_errata&.pluck(:id))
31
+ ::Katello::ContentFacetErratum.where(erratum_id: dup_errata&.map(&:id)).each do |host_erratum|
32
+ if ::Katello::ContentFacetErratum.find_by(content_facet_id: host_erratum.content_facet_id, erratum_id: errata_to_keep.id)
33
+ host_erratum.delete
34
+ else
35
+ host_erratum.update(erratum_id: errata_to_keep.id)
36
+ end
37
+ end
38
+ dup_errata_ids = dup_errata&.pluck(:id)
39
+
40
+ erratum_packages = ::Katello::ErratumPackage.where(:erratum_id => dup_errata_ids)
41
+ erratum_packages.each do |dup_err_package|
42
+ erratum_package_to_keep = ::Katello::ErratumPackage.find_by(erratum_id: errata_to_keep.id, nvrea: dup_err_package.nvrea)
43
+ ::Katello::ModuleStreamErratumPackage.where(erratum_package_id: dup_err_package).each do |dup_mod_errata_package|
44
+ if ::Katello::ModuleStreamErratumPackage.find_by(module_stream_id: dup_mod_errata_package.module_stream_id, erratum_package_id: erratum_package_to_keep&.id)
45
+ dup_mod_errata_package.delete
46
+ else
47
+ begin
48
+ dup_mod_errata_package.update(erratum_package_id: erratum_package_to_keep&.id)
49
+ rescue
50
+ dup_mod_errata_package.delete
51
+ end
52
+ end
53
+ end
54
+ end
55
+
56
+ dup_errata_ids = dup_errata&.pluck(:id)
57
+ if dup_errata_ids&.present?
58
+ erratum_packages = ::Katello::ErratumPackage.where(:erratum_id => dup_errata_ids)
59
+ ::Katello::ModuleStreamErratumPackage.where(erratum_package_id: erratum_packages).delete_all
60
+ erratum_packages.delete_all
61
+ ::Katello::ErratumBugzilla.where(:erratum_id => dup_errata_ids).delete_all
62
+ ::Katello::ErratumCve.where(:erratum_id => dup_errata_ids).delete_all
63
+ ::Katello::Erratum.where(:id => dup_errata_ids).delete_all
64
+ end
28
65
  end
29
66
  end
30
67
 
68
+ # rubocop:enable Metrics/MethodLength
69
+ # rubocop:enable Metrics/AbcSize
70
+ # rubocop:enable Metrics/CyclomaticComplexity
71
+ # rubocop:enable Metrics/PerceivedComplexity
31
72
  def down
32
- fail ActiveRecord::IrreversibleMigration
73
+ #Don't do anything on reverse
33
74
  end
34
75
  end
@@ -10,7 +10,7 @@
10
10
  angular.module('Bastion.repositories').service('MirroringPolicy',
11
11
  ['translate', function (translate) {
12
12
 
13
- this.defaultMirroringPolicy = 'additive';
13
+ this.defaultMirroringPolicy = 'mirror_content_only';
14
14
 
15
15
  this.mirroringPolicies = function(repoType) {
16
16
  var policies = {
@@ -1,3 +1,3 @@
1
1
  module Katello
2
- VERSION = "4.4.0".freeze
2
+ VERSION = "4.4.1".freeze
3
3
  end
@@ -1,18 +1,33 @@
1
1
  import React from 'react';
2
2
  import { shape, string, number, element, arrayOf } from 'prop-types';
3
3
  import { Tab, Tabs, TabTitleText } from '@patternfly/react-core';
4
- import { Switch, Route, Redirect, useLocation, withRouter, HashRouter } from 'react-router-dom';
4
+ import { Switch, Route, Redirect, useHistory, useLocation, withRouter, HashRouter } from 'react-router-dom';
5
5
  import { head, last } from 'lodash';
6
6
 
7
7
  const RoutedTabs = ({
8
8
  tabs, defaultTabIndex,
9
9
  }) => {
10
+ const { push } = useHistory();
10
11
  const {
11
12
  hash, key: locationKey,
12
13
  } = useLocation();
13
14
 
14
15
  // The below transforms #/history/6 to history
15
16
  const currentTabFromUrl = head(last(hash.split('#/')).split('/'));
17
+ // Allows navigation back to mainTab
18
+ const onSubTab = currentTabFromUrl !== last(last(hash.split('#/')).split('/'));
19
+
20
+ const onSelect = (e, key) => {
21
+ e.preventDefault();
22
+ // See the below links for understanding of this mouseEvent
23
+ // https://www.w3schools.com/jsref/event_which.asp
24
+ // https://www.w3schools.com/jsref/event_button.asp
25
+ const middleMouseButtonNotUsed = !(e.button === 1 || e.buttons === 4 || e.which === 2);
26
+ const notCurrentTab = currentTabFromUrl !== key;
27
+ if (middleMouseButtonNotUsed && (notCurrentTab || !!onSubTab)) {
28
+ push(`#/${key}`);
29
+ }
30
+ };
16
31
 
17
32
  return (
18
33
  <>
@@ -24,6 +39,7 @@ const RoutedTabs = ({
24
39
  <a
25
40
  key={key}
26
41
  href={`#/${key}`}
42
+ onMouseUp={e => onSelect(e, key)}
27
43
  style={{ textDecoration: 'none' }}
28
44
  >
29
45
  <Tab
@@ -115,7 +115,7 @@ const CreateContentViewForm = ({ setModalOpen }) => {
115
115
  aria-label="component_tile"
116
116
  icon={<ContentViewIcon composite={false} />}
117
117
  id="component"
118
- title={__('Component content view')}
118
+ title={__('Content view')}
119
119
  onClick={() => { setComponent(true); setComposite(false); }}
120
120
  isSelected={component}
121
121
  >
@@ -133,7 +133,7 @@ const CreateContentViewForm = ({ setModalOpen }) => {
133
133
  onClick={() => { setComposite(true); setComponent(false); }}
134
134
  isSelected={composite}
135
135
  >
136
- {__('Consisting of multiple component content views')}
136
+ {__('Consisting of multiple content views')}
137
137
  </Tile>
138
138
  </GridItem>
139
139
  </Grid>
@@ -68,7 +68,7 @@ test('Displays dependent fields correctly', () => {
68
68
  expect(getByText('Name')).toBeInTheDocument();
69
69
  expect(getByText('Label')).toBeInTheDocument();
70
70
  expect(getByText('Composite content view')).toBeInTheDocument();
71
- expect(getByText('Component content view')).toBeInTheDocument();
71
+ expect(getByText('Content view')).toBeInTheDocument();
72
72
  expect(getByText('Solve dependencies')).toBeInTheDocument();
73
73
  expect(queryByText('Auto publish')).not.toBeInTheDocument();
74
74
  expect(getByText('Import only')).toBeInTheDocument();
@@ -87,7 +87,7 @@ const ComponentContentViewAddModal = ({
87
87
 
88
88
  return (
89
89
  <Modal
90
- title={componentId ? __('Update version') : __('Add component')}
90
+ title={componentId ? __('Update version') : __('Add content view')}
91
91
  variant={ModalVariant.small}
92
92
  isOpen={show}
93
93
  description={__(`Select available version of ${cvName} to use`)}
@@ -51,10 +51,10 @@ const ComponentContentViewBulkAddModal = ({ cvId, rowsToAdd, onClose }) => {
51
51
 
52
52
  return (
53
53
  <Modal
54
- title={__('Add component content views')}
54
+ title={__('Add content views')}
55
55
  variant={ModalVariant.large}
56
56
  isOpen
57
- description={__('Select available version of components to use')}
57
+ description={__('Select available version of content views to use')}
58
58
  onClose={onClose}
59
59
  appendTo={document.body}
60
60
  >
@@ -212,7 +212,7 @@ test('Can add published component views to content view with modal', async (done
212
212
  });
213
213
  fireEvent.click(getByText('Add'));
214
214
  await patientlyWaitFor(() => {
215
- expect(getByText('Add component')).toBeInTheDocument();
215
+ expect(getByText('Add content view')).toBeInTheDocument();
216
216
  });
217
217
  fireEvent.click(getByLabelText('add_component'));
218
218
  await patientlyWaitFor(() => {
@@ -317,7 +317,7 @@ test('Can bulk add component views to content view with modal', async (done) =>
317
317
  .reply(200, {});
318
318
 
319
319
  const {
320
- getByText, getByLabelText, queryByText,
320
+ getAllByText, getByLabelText, queryByText,
321
321
  } = renderWithRedux(
322
322
  <ContentViewComponents cvId={4} details={cvDetails} />,
323
323
  renderOptions,
@@ -333,14 +333,14 @@ test('Can bulk add component views to content view with modal', async (done) =>
333
333
  });
334
334
  fireEvent.click(getByLabelText('bulk_add_components'));
335
335
  await patientlyWaitFor(() => {
336
- expect(getByText('Add component content views')).toBeInTheDocument();
336
+ expect(getAllByText('Add content views')[1]).toBeInTheDocument();
337
337
  });
338
338
  fireEvent.click(getByLabelText('version-select-cv-10'));
339
339
  fireEvent.click(getByLabelText('cv-10-3.0'));
340
340
 
341
341
  fireEvent.click(getByLabelText('add_components'));
342
342
  await patientlyWaitFor(() => {
343
- expect(queryByText('Add component content views')).not.toBeInTheDocument();
343
+ expect(queryByText('Select available version of content views to use')).not.toBeInTheDocument();
344
344
  expect(getByLabelText('bulk_add_components')).toHaveAttribute('aria-disabled', 'false');
345
345
  });
346
346
 
@@ -70,7 +70,7 @@ const ContentViewInfo = ({ cvId, details }) => {
70
70
  <TextListItem component={TextListItemVariants.dd} className="foreman-spaced-list">
71
71
  <Flex>
72
72
  <FlexItem spacer={{ default: 'spacerXs' }}>
73
- <ContentViewIcon composite={composite} description={composite ? __('Composite') : __('Component')} />
73
+ <ContentViewIcon composite={composite} description={composite ? __('Composite') : __('Content view')} />
74
74
  </FlexItem>
75
75
  </Flex>
76
76
  </TextListItem>
@@ -43,14 +43,14 @@ test('Can call API for CVs and show on screen on page load', async (done) => {
43
43
  .query(true)
44
44
  .reply(200, cvIndexData);
45
45
 
46
- const { queryByText } = renderWithRedux(<ContentViewsPage />, renderOptions);
46
+ const { queryByText, queryAllByText } = renderWithRedux(<ContentViewsPage />, renderOptions);
47
47
 
48
48
  expect(queryByText(firstCV.name)).toBeNull();
49
49
 
50
50
  // Assert that the CV name is now showing on the screen, but wait for it to appear.
51
51
  await patientlyWaitFor(() => {
52
52
  expect(queryByText(firstCV.name)).toBeInTheDocument();
53
- expect(queryByText('Component content views')).toBeInTheDocument();
53
+ expect(queryAllByText('Content views')[0]).toBeInTheDocument();
54
54
  expect(queryByText('Composite content views')).toBeInTheDocument();
55
55
  });
56
56
 
@@ -354,7 +354,7 @@ test('Displays Create Content View and opens modal with Form', async () => {
354
354
  expect(queryByText('Name')).not.toBeInTheDocument();
355
355
  expect(queryByText('Label')).not.toBeInTheDocument();
356
356
  expect(queryByText('Composite content view')).not.toBeInTheDocument();
357
- expect(queryByText('Component content view')).not.toBeInTheDocument();
357
+ expect(queryByText('Content view')).not.toBeInTheDocument();
358
358
  expect(queryByText('Solve dependencies')).not.toBeInTheDocument();
359
359
  expect(queryByText('Auto publish')).not.toBeInTheDocument();
360
360
  expect(queryByText('Import only')).not.toBeInTheDocument();
@@ -365,7 +365,7 @@ test('Displays Create Content View and opens modal with Form', async () => {
365
365
  expect(getByText('Name')).toBeInTheDocument();
366
366
  expect(getByText('Label')).toBeInTheDocument();
367
367
  expect(getByText('Composite content view')).toBeInTheDocument();
368
- expect(getByText('Component content view')).toBeInTheDocument();
368
+ expect(getByText('Content view')).toBeInTheDocument();
369
369
  expect(getByText('Solve dependencies')).toBeInTheDocument();
370
370
  expect(queryByText('Auto publish')).not.toBeInTheDocument();
371
371
  expect(getByText('Import only')).toBeInTheDocument();
@@ -18,7 +18,7 @@ const ContentViewsCounter = () => {
18
18
  <b>
19
19
  <Flex>
20
20
  <FlexItem spacer={{ default: 'spacerXs' }}>
21
- <ContentViewIcon composite={false} description={__('Component content views')} count={(component || component === 0) ? component : <InProgressIcon />} />
21
+ <ContentViewIcon composite={false} description={__('Content views')} count={(component || component === 0) ? component : <InProgressIcon />} />
22
22
  </FlexItem>
23
23
  <FlexItem>
24
24
  <Tooltip
@@ -14,14 +14,14 @@ const DetailsExpansion = ({
14
14
  if (cvComposite) {
15
15
  return (
16
16
  <>
17
- {__('Related component cvs: ')}
17
+ {__('Related content views: ')}
18
18
  <RelatedContentViewComponentsModal key="cvId" {...{ cvName, cvId, relatedCVCount }} />
19
19
  </>
20
20
  );
21
21
  }
22
22
  return (
23
23
  <>
24
- {__('Related composite cvs: ')}
24
+ {__('Related composite content views: ')}
25
25
  <RelatedCompositeContentViewsModal
26
26
  key={cvId}
27
27
  {...{
@@ -29,7 +29,7 @@ const RelatedContentViewsModal = ({ cvName, cvId, relatedCVCount }) => {
29
29
  <FlexItem>
30
30
  <RegistryIcon />
31
31
  <b>{` ${cvName}`}</b>
32
- {__(' content view is used in listed component content views. For more information, ')}
32
+ {__(' content view is used in listed content views. For more information, ')}
33
33
  <Link to={urlBuilder(`content_views/${cvId}#/contentviews`, '')}>
34
34
  {__('view content view tabs.')}
35
35
  </Link>
@@ -49,7 +49,7 @@ const RelatedContentViewsModal = ({ cvName, cvId, relatedCVCount }) => {
49
49
  <Grid>
50
50
  <GridItem span={12}>
51
51
  <Modal
52
- title={__('Related component content views')}
52
+ title={__('Related content views')}
53
53
  variant={ModalVariant.medium}
54
54
  isOpen={isOpen}
55
55
  description={description()}
@@ -30,7 +30,7 @@ test('Can call API and show Related Content Views Components Modal', async (done
30
30
 
31
31
  await patientlyWaitFor(() => expect(getByLabelText(`button_${cvId}`)).toBeInTheDocument());
32
32
  fireEvent.click(getByLabelText(`button_${cvId}`));
33
- await patientlyWaitFor(() => expect(getByText('Related component content views')).toBeInTheDocument());
33
+ await patientlyWaitFor(() => expect(getByText('Related content views')).toBeInTheDocument());
34
34
 
35
35
  assertNockRequest(scope, done);
36
36
  });
@@ -1,7 +1,6 @@
1
1
  import React from 'react';
2
2
  import { translate as __ } from 'foremanReact/common/I18n';
3
3
  import ModuleStreamDetailArtifacts from './ModuleStreamDetailArtifacts';
4
- import ModuleStreamDetailProfiles from './Profiles/ModuleStreamDetailProfiles';
5
4
  import ContentDetailInfo from '../../../components/Content/Details/ContentDetailInfo';
6
5
  import ContentDetailRepositories from '../../../components/Content/Details/ContentDetailRepositories';
7
6
 
@@ -17,7 +16,7 @@ export const displayMap = new Map([
17
16
  ]);
18
17
 
19
18
  export default (detailInfo) => {
20
- const { repositories, profiles, artifacts } = detailInfo;
19
+ const { repositories, artifacts } = detailInfo;
21
20
 
22
21
  return [
23
22
  {
@@ -37,14 +36,6 @@ export default (detailInfo) => {
37
36
  },
38
37
  {
39
38
  key: 3,
40
- tabHeader: __('Profiles'),
41
- tabContent: (profiles && profiles.length ?
42
- <ModuleStreamDetailProfiles profiles={profiles} /> :
43
- __('No profiles to show')
44
- ),
45
- },
46
- {
47
- key: 4,
48
39
  tabHeader: __('Artifacts'),
49
40
  tabContent: (artifacts && artifacts.length ?
50
41
  <ModuleStreamDetailArtifacts artifacts={artifacts} /> :
@@ -44,21 +44,20 @@ class ModuleStreamDetails extends Component {
44
44
  return (
45
45
  <div>
46
46
  {!loading && <BreadcrumbsBar
47
+ isLoadingResources={loading}
47
48
  onSwitcherItemClick={(e, url) => this.handleBreadcrumbSwitcherItem(e, url)}
48
- data={{
49
- isSwitchable: true,
50
- breadcrumbItems: [
51
- {
52
- caption: __('Module Streams'),
53
- onClick: () =>
54
- this.props.history.push('/module_streams'),
55
- },
56
- {
57
- caption: `${name} ${stream}`,
58
- },
59
- ],
60
- resource,
61
- }}
49
+ isSwitchable
50
+ breadcrumbItems={[
51
+ {
52
+ caption: __('Module Streams'),
53
+ onClick: () =>
54
+ this.props.history.push('/module_streams'),
55
+ },
56
+ {
57
+ caption: `${name} ${stream}`,
58
+ },
59
+ ]}
60
+ resource={resource}
62
61
  />}
63
62
  <ContentDetails
64
63
  contentDetails={moduleStreamDetails}
@@ -76,11 +76,6 @@ exports[`Module stream details page rendering renders with loading state 1`] = `
76
76
  },
77
77
  Object {
78
78
  "key": 3,
79
- "tabContent": "No profiles to show",
80
- "tabHeader": "Profiles",
81
- },
82
- Object {
83
- "key": 4,
84
79
  "tabContent": "No artifacts to show",
85
80
  "tabHeader": "Artifacts",
86
81
  },
@@ -93,26 +88,26 @@ exports[`Module stream details page rendering renders with loading state 1`] = `
93
88
  exports[`Module stream details page rendering renders with module stream provided 1`] = `
94
89
  <div>
95
90
  <BreadcrumbsBar
96
- data={
97
- Object {
98
- "breadcrumbItems": Array [
99
- Object {
100
- "caption": "Module Streams",
101
- "onClick": [Function],
102
- },
103
- Object {
104
- "caption": "avocado latest",
105
- },
106
- ],
107
- "isSwitchable": true,
108
- "resource": Object {
109
- "nameField": "name",
110
- "resourceUrl": "/katello/api/v2/module_streams",
111
- "switcherItemUrl": "/module_streams/:id",
91
+ breadcrumbItems={
92
+ Array [
93
+ Object {
94
+ "caption": "Module Streams",
95
+ "onClick": [Function],
112
96
  },
113
- }
97
+ Object {
98
+ "caption": "avocado latest",
99
+ },
100
+ ]
114
101
  }
102
+ isSwitchable={true}
115
103
  onSwitcherItemClick={[Function]}
104
+ resource={
105
+ Object {
106
+ "nameField": "name",
107
+ "resourceUrl": "/katello/api/v2/module_streams",
108
+ "switcherItemUrl": "/module_streams/:id",
109
+ }
110
+ }
116
111
  />
117
112
  <ContentDetails
118
113
  contentDetails={
@@ -397,84 +392,6 @@ exports[`Module stream details page rendering renders with module stream provide
397
392
  },
398
393
  Object {
399
394
  "key": 3,
400
- "tabContent": <ModuleStreamDetailProfiles
401
- profiles={
402
- Array [
403
- Object {
404
- "id": 37,
405
- "name": "default",
406
- "rpms": Array [
407
- Object {
408
- "id": 108,
409
- "name": "perl",
410
- },
411
- Object {
412
- "id": 110,
413
- "name": "foo",
414
- },
415
- Object {
416
- "id": 111,
417
- "name": "rpm_0",
418
- },
419
- Object {
420
- "id": 112,
421
- "name": "rpm_1",
422
- },
423
- Object {
424
- "id": 113,
425
- "name": "rpm_2",
426
- },
427
- Object {
428
- "id": 114,
429
- "name": "rpm_3",
430
- },
431
- Object {
432
- "id": 115,
433
- "name": "rpm_4",
434
- },
435
- Object {
436
- "id": 116,
437
- "name": "rpm_5",
438
- },
439
- Object {
440
- "id": 117,
441
- "name": "rpm_6",
442
- },
443
- Object {
444
- "id": 118,
445
- "name": "rpm_7",
446
- },
447
- Object {
448
- "id": 119,
449
- "name": "rpm_8",
450
- },
451
- Object {
452
- "id": 120,
453
- "name": "rpm_9",
454
- },
455
- Object {
456
- "id": 121,
457
- "name": "rpm_10",
458
- },
459
- ],
460
- },
461
- Object {
462
- "id": 38,
463
- "name": "minimal",
464
- "rpms": Array [
465
- Object {
466
- "id": 84,
467
- "name": "python2-avocado",
468
- },
469
- ],
470
- },
471
- ]
472
- }
473
- />,
474
- "tabHeader": "Profiles",
475
- },
476
- Object {
477
- "key": 4,
478
395
  "tabContent": <ModuleStreamDetailArtifacts
479
396
  artifacts={
480
397
  Array [
@@ -9,5 +9,6 @@ export const CDN_CONFIGURATION_TYPES = {
9
9
  airgapped: __('Air-gapped'),
10
10
  };
11
11
 
12
+ export const DEFAULT_ORGANIZATION_LABEL = 'Default_Organization';
12
13
  export const DEFAULT_CONTENT_VIEW_LABEL = 'Default_Organization_View';
13
14
  export const DEFAULT_LIFECYCLE_ENVIRONMENT_LABEL = 'Library';
@@ -18,7 +18,7 @@ import {
18
18
  import { translate as __ } from 'foremanReact/common/I18n';
19
19
  import { noop } from 'foremanReact/common/helpers';
20
20
 
21
- import { UPSTREAM_SERVER, DEFAULT_CONTENT_VIEW_LABEL, DEFAULT_LIFECYCLE_ENVIRONMENT_LABEL } from './CdnConfigurationConstants';
21
+ import { UPSTREAM_SERVER, DEFAULT_CONTENT_VIEW_LABEL, DEFAULT_LIFECYCLE_ENVIRONMENT_LABEL, DEFAULT_ORGANIZATION_LABEL } from './CdnConfigurationConstants';
22
22
  import EditableTextInput from '../../../../components/EditableTextInput';
23
23
 
24
24
  import {
@@ -37,15 +37,17 @@ const UpstreamServerTypeForm = ({
37
37
  const [username, setUsername] = useState(cdnConfiguration.username);
38
38
  const [password, setPassword] = useState(null);
39
39
  const [organizationLabel, setOrganizationLabel] =
40
- useState(cdnConfiguration.upstream_organization_label);
40
+ useState(cdnConfiguration.upstream_organization_label || DEFAULT_ORGANIZATION_LABEL);
41
41
  const [sslCaCredentialId, setSslCaCredentialId] = useState(cdnConfiguration.ssl_ca_credential_id);
42
42
  const updatingCdnConfiguration = useSelector(state => selectUpdatingCdnConfiguration(state));
43
43
 
44
44
  const [contentViewLabel, setContentViewLabel] =
45
- useState(cdnConfiguration.upstream_content_view_label);
45
+ useState(cdnConfiguration.upstream_content_view_label ||
46
+ DEFAULT_CONTENT_VIEW_LABEL);
46
47
 
47
48
  const [lifecycleEnvironmentLabel, setLifecycleEnvironmentLabel] =
48
- useState(cdnConfiguration.upstream_lifecycle_environment_label);
49
+ useState(cdnConfiguration.upstream_lifecycle_environment_label ||
50
+ DEFAULT_LIFECYCLE_ENVIRONMENT_LABEL);
49
51
 
50
52
  const [updateEnabled, setUpdateEnabled] = useState(false);
51
53
 
@@ -85,7 +87,7 @@ const UpstreamServerTypeForm = ({
85
87
  url,
86
88
  username,
87
89
  password,
88
- upstream_organization_label: organizationLabel,
90
+ upstream_organization_label: organizationLabel || DEFAULT_ORGANIZATION_LABEL,
89
91
  ssl_ca_credential_id: sslCaCredentialId,
90
92
  upstream_content_view_label: contentViewLabel || DEFAULT_CONTENT_VIEW_LABEL,
91
93
  upstream_lifecycle_environment_label: lifecycleEnvironmentLabel ||
@@ -184,7 +186,7 @@ const UpstreamServerTypeForm = ({
184
186
  <TextInput
185
187
  aria-label="cdn-lifecycle-environment-label"
186
188
  type="text"
187
- value={lifecycleEnvironmentLabel || DEFAULT_LIFECYCLE_ENVIRONMENT_LABEL}
189
+ value={lifecycleEnvironmentLabel || ''}
188
190
  isDisabled={updatingCdnConfiguration}
189
191
  onChange={setLifecycleEnvironmentLabel}
190
192
  />
@@ -195,7 +197,7 @@ const UpstreamServerTypeForm = ({
195
197
  <TextInput
196
198
  aria-label="cdn-content-view-label"
197
199
  type="text"
198
- value={contentViewLabel || DEFAULT_CONTENT_VIEW_LABEL}
200
+ value={contentViewLabel || ''}
199
201
  isDisabled={updatingCdnConfiguration}
200
202
  onChange={setContentViewLabel}
201
203
  />
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.4.0
4
+ version: 4.4.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: 2022-03-18 00:00:00.000000000 Z
11
+ date: 2022-05-27 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rails