katello 3.4.0.2 → 3.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 (45) hide show
  1. checksums.yaml +4 -4
  2. data/app/assets/javascripts/katello/hosts/host_and_hostgroup_edit.js +2 -27
  3. data/app/controllers/katello/api/rhsm/candlepin_proxies_controller.rb +3 -4
  4. data/app/controllers/katello/api/v2/activation_keys_controller.rb +5 -1
  5. data/app/controllers/katello/api/v2/host_subscriptions_controller.rb +5 -1
  6. data/app/controllers/katello/api/v2/repositories_controller.rb +2 -2
  7. data/app/lib/actions/katello/product/create.rb +4 -0
  8. data/app/lib/actions/pulp/consumer/generate_applicability.rb +1 -5
  9. data/app/lib/actions/pulp/repository/update_importer.rb +8 -0
  10. data/app/lib/katello/resources/cdn.rb +20 -5
  11. data/app/models/katello/activation_key.rb +22 -3
  12. data/app/models/katello/candlepin/content.rb +2 -10
  13. data/app/models/katello/errata_status.rb +2 -2
  14. data/app/models/katello/glue/provider.rb +4 -2
  15. data/app/models/katello/glue/pulp/repo.rb +2 -2
  16. data/app/models/katello/product.rb +3 -2
  17. data/app/models/katello/provider.rb +0 -7
  18. data/app/models/katello/repository.rb +9 -0
  19. data/app/services/katello/candlepin/consumer.rb +22 -2
  20. data/app/views/foreman/smart_proxies/_content_sync.html.erb +1 -1
  21. data/app/views/katello/api/v2/content_facet/base.json.rabl +1 -0
  22. data/app/views/katello/api/v2/errata/_counts.json.rabl +10 -8
  23. data/app/views/katello/api/v2/hostgroups_extensions/show.json.rabl +1 -1
  24. data/db/seeds.d/75-job_templates.rb +6 -1
  25. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/activation-keys/details/activation-key-repository-sets.controller.js +14 -4
  26. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/activation-keys/details/views/activation-key-details.html +3 -12
  27. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/activation-keys/details/views/activation-key-repository-sets.html +13 -10
  28. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/common/api-error-handler.service.js +13 -5
  29. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/common/select-action-dropdown.directive.js +45 -0
  30. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/common/views/select-action-dropdown.html +10 -0
  31. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/content-hosts/details/content-host-repository-sets.controller.js +14 -4
  32. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/content-hosts/details/views/content-host-repository-sets.html +14 -12
  33. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/content-hosts/views/content-hosts.html +2 -10
  34. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/content-views/details/views/content-view-details.html +24 -32
  35. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/docker-tags/details/views/docker-tag-info.html +2 -2
  36. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/host-collections/details/views/host-collection-details.html +2 -11
  37. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/ostree-branches/details/views/ostree-branch-repositories.html +1 -1
  38. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/products/details/repositories/details/views/repository-details.html +3 -12
  39. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/products/details/views/product-details.html +3 -11
  40. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/products/views/products.html +2 -11
  41. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/sync-plans/details/views/sync-plan-details.html +3 -12
  42. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/sync-plans/details/views/sync-plan-products.html +1 -1
  43. data/lib/katello/plugin.rb +4 -4
  44. data/lib/katello/version.rb +1 -1
  45. metadata +4 -2
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 3d557071b61f046420cf06747c4efd13d0702ae3
4
- data.tar.gz: fa24cacf3873c9bd36814ff44b1dd9a8d99ccd76
3
+ metadata.gz: a69d7fd688dc60f6918570d9a46f180c5837b95b
4
+ data.tar.gz: f59ba04326eeec8fbb1582ff99b6b118ae04de3d
5
5
  SHA512:
6
- metadata.gz: 2dafe3130a294d08dd05f4996b91a3451fbf1217b0a9e063410119c21e26c7a09c0b1572f6ae6030d3228f45e48aa02e0a1a2bc3dcb8bee2689262a98e1cfdc4
7
- data.tar.gz: 5a7753c722ad029191c9d7a3b46c1f59d3b5587b84d6ef6391478973f9eca151c5965742777f8d4209d52a38ff6806bd695cc368a0c0abeac5fe6686fead9375
6
+ metadata.gz: 1ba9d1e9c4b60b6cbb207bfcf911c21b08fa705e661ce855104cf23d5bacaf843dc7a685cabc179f1f3cd8fbc80140147c551f499f097970de7e1f9a360b7822
7
+ data.tar.gz: 299af24880144ecdc9b3fd6215fb26170e3f08c94aa17150721289ecd4807c5b724244342b7f7cb2865e5652f7d8d641d05df1b5f6d2a71de6b4d3f852f412fd
@@ -3,6 +3,8 @@ KT.hosts = {};
3
3
 
4
4
  $(document).on('ContentLoad', function(){
5
5
  KT.hosts.onKatelloHostEditLoad();
6
+ window.tfm.hosts.registerPluginAttributes("os",
7
+ ['lifecycle_environment_id', 'content_view_id', 'environment_id', 'content_source_id', 'architecture_id']);
6
8
 
7
9
  $("#hostgroup_lifecycle_environment_id").change(KT.hosts.fetchContentViews);
8
10
  $("#host_lifecycle_environment_id").change(KT.hosts.fetchContentViews);
@@ -248,30 +250,3 @@ KT.hosts.set_media_selection_bindings = function() {
248
250
  KT.hosts.set_synced_content_bindings();
249
251
  KT.hosts.get_media_selector_elements().change(KT.hosts.media_selection_changed);
250
252
  };
251
-
252
- // Note we are overriding the os_selected method in foreman
253
- // Hopefully when this gets resolved http://projects.theforeman.org/issues/14699
254
- // This method will get backed out.
255
- function os_selected(element){
256
- var url = $(element).attr('data-url');
257
- var type = $(element).attr('data-type');
258
- var attrs = {};
259
- attrs[type] = attribute_hash(['operatingsystem_id', 'organization_id', 'location_id', 'content_view_id',
260
- 'lifecycle_environment_id', 'content_source_id', 'architecture_id', 'hostgroup_id',
261
- 'medium_id', 'kickstart_repository_id']);
262
- tfm.tools.showSpinner();
263
- $.ajax({
264
- data: attrs,
265
- type:'post',
266
- url: url,
267
- complete: function(){
268
- reloadOnAjaxComplete(element);
269
- },
270
- success: function(request) {
271
- $('#media_select').html(request);
272
- reload_host_params();
273
- reload_puppetclass_params();
274
- }
275
- });
276
- update_provisioning_image();
277
- };
@@ -114,8 +114,7 @@ module Katello
114
114
  # Note that this request comes in as content-type 'text/plain' so that
115
115
  # tomcat won't parse the json. Here we just pass the plain body through to candlepin
116
116
  def async_hypervisors_update
117
- raw_json = request.body.string
118
- task = Katello::Resources::Candlepin::Consumer.async_hypervisors(params[:owner], raw_json)
117
+ task = Katello::Resources::Candlepin::Consumer.async_hypervisors(params[:owner], request.raw_post)
119
118
  async_task(::Actions::Katello::Host::Hypervisors, nil, :task_id => task['id'])
120
119
 
121
120
  render :json => task
@@ -137,7 +136,7 @@ module Katello
137
136
  #param :date, String, :desc => N_("check-in time")
138
137
  def consumer_checkin
139
138
  @host.update_attributes(:last_checkin => params[:date])
140
- Candlepin::Consumer.new(@host.subscription_facet.uuid).checkin(params[:date])
139
+ Candlepin::Consumer.new(@host.subscription_facet.uuid, @host.organization.label).checkin(params[:date])
141
140
  render :json => Resources::Candlepin::Consumer.get(@host.subscription_facet.uuid)
142
141
  end
143
142
 
@@ -165,7 +164,7 @@ module Katello
165
164
  #desc 'Schedules the consumer identity certificate regeneration'
166
165
  def regenerate_identity_certificates
167
166
  uuid = @host.subscription_facet.uuid
168
- Candlepin::Consumer.new(uuid).regenerate_identity_certificates
167
+ Candlepin::Consumer.new(uuid, @host.organization.label).regenerate_identity_certificates
169
168
  render :json => Resources::Candlepin::Consumer.get(uuid)
170
169
  end
171
170
 
@@ -131,8 +131,12 @@ module Katello
131
131
 
132
132
  api :GET, "/activation_keys/:id/product_content", N_("Show content available for an activation key")
133
133
  param :id, String, :desc => N_("ID of the activation key"), :required => true
134
+ param :content_access_mode_all, :bool, :desc => N_("Get all content available, not just that provided by subscriptions")
135
+ param :content_access_mode_env, :bool, :desc => N_("Limit content to just that available in the activation key's content view version")
134
136
  def product_content
135
- content = @activation_key.available_content
137
+ content_access_mode_all = ::Foreman::Cast.to_bool(params[:content_access_mode_all])
138
+ content_access_mode_env = ::Foreman::Cast.to_bool(params[:content_access_mode_env])
139
+ content = @activation_key.available_content(content_access_mode_all, content_access_mode_env)
136
140
  response = {
137
141
  :results => content,
138
142
  :total => content.size,
@@ -167,8 +167,12 @@ module Katello
167
167
 
168
168
  api :GET, "/hosts/:host_id/subscriptions/product_content", N_("Get content and overrides for the host")
169
169
  param :host_id, String, :desc => N_("Id of the host"), :required => true
170
+ param :content_access_mode_all, :bool, :desc => N_("Get all content available, not just that provided by subscriptions")
171
+ param :content_access_mode_env, :bool, :desc => N_("Limit content to just that available in the host's content view version")
170
172
  def product_content
171
- content = @host.subscription_facet.candlepin_consumer.available_product_content
173
+ content_access_mode_all = ::Foreman::Cast.to_bool(params[:content_access_mode_all])
174
+ content_access_mode_env = ::Foreman::Cast.to_bool(params[:content_access_mode_env])
175
+ content = @host.subscription_facet.candlepin_consumer.available_product_content(content_access_mode_all, content_access_mode_env)
172
176
  overrides = @host.subscription_facet.candlepin_consumer.content_overrides
173
177
  results = content.map { |product_content| Katello::ProductContentPresenter.new(product_content, overrides) }
174
178
 
@@ -366,9 +366,9 @@ module Katello
366
366
  upload_ids = uploads.map { |upload| upload['id'] }
367
367
  unit_keys = uploads.map do |upload|
368
368
  if @repository.file?
369
- upload.except('id').except('name')
370
- else
371
369
  upload.except('id')
370
+ else
371
+ upload.except('id').except('name')
372
372
  end
373
373
  end
374
374
 
@@ -29,6 +29,10 @@ module Actions
29
29
  end
30
30
  end
31
31
 
32
+ def run
33
+ ::Katello::Repository.ensure_sync_notification
34
+ end
35
+
32
36
  def finalize
33
37
  product = ::Katello::Product.find(input[:product][:id])
34
38
  product.cp_id = input[:cp_id]
@@ -7,11 +7,7 @@ module Actions
7
7
  end
8
8
 
9
9
  def invoke_external_task
10
- if input[:uuids].length == 1
11
- pulp_resources.consumer.regenerate_applicability_by_id(input[:uuids].first)
12
- else
13
- pulp_extensions.consumer.regenerate_applicability_by_ids(input[:uuids])
14
- end
10
+ pulp_extensions.consumer.regenerate_applicability_by_ids(input[:uuids])
15
11
  end
16
12
  end
17
13
  end
@@ -10,6 +10,14 @@ module Actions
10
10
  end
11
11
 
12
12
  def run
13
+ # Update ssl options by themselves workaround for https://pulp.plan.io/issues/2727
14
+ ssl_ca_cert = input[:config].delete('ssl_ca_cert')
15
+ ssl_client_cert = input[:config].delete('ssl_client_cert')
16
+ ssl_client_key = input[:config].delete('ssl_client_key')
17
+
18
+ output[:response] = pulp_resources.repository.
19
+ update_importer(input[:repo_id], input[:id], :ssl_client_cert => ssl_client_cert,
20
+ :ssl_client_key => ssl_client_key, :ssl_ca_cert => ssl_ca_cert)
13
21
  output[:response] = pulp_resources.repository.
14
22
  update_importer(*input.values_at(:repo_id, :id, :config))
15
23
  end
@@ -29,9 +29,16 @@ module Katello
29
29
  options.reverse_merge!(:verify_ssl => 9)
30
30
  options.assert_valid_keys(:ssl_client_key, :ssl_client_cert, :ssl_ca_file, :verify_ssl,
31
31
  :product)
32
- if options[:ssl_client_cert]
33
- options.reverse_merge!(:ssl_ca_file => CdnResource.ca_file)
32
+
33
+ ca = Katello::Repository.feed_ca_file(url)
34
+ if ca && URI(url).scheme == 'https'
35
+ options.reverse_merge!(:ssl_ca_file => ca)
36
+ elsif URI(url).scheme == 'https'
37
+ store = OpenSSL::X509::Store.new
38
+ store.set_default_paths
39
+ options.reverse_merge!(:cert_store => store)
34
40
  end
41
+
35
42
  load_proxy_settings
36
43
  @product = options[:product]
37
44
 
@@ -40,13 +47,21 @@ module Katello
40
47
  @options = options
41
48
  end
42
49
 
50
+ def self.redhat_cdn?(url)
51
+ url.include?(SETTINGS[:katello][:redhat_repository_url])
52
+ end
53
+
43
54
  def http_downloader
44
55
  net = net_http_class.new(@uri.host, @uri.port)
45
56
  net.use_ssl = @uri.is_a?(URI::HTTPS)
46
57
 
47
- net.cert = @options[:ssl_client_cert]
48
- net.key = @options[:ssl_client_key]
49
- net.ca_file = @options[:ssl_ca_file]
58
+ if CdnResource.redhat_cdn?(@uri.to_s)
59
+ net.cert = @options[:ssl_client_cert]
60
+ net.key = @options[:ssl_client_key]
61
+ net.ca_file = @options[:ssl_ca_file] if @options[:ssl_ca_file]
62
+ else
63
+ net.cert_store = @options[:cert_store]
64
+ end
50
65
 
51
66
  # NOTE: This was added because some proxies dont support SSLv23 and do not handle TLS 1.2
52
67
  # Valid values in ruby 1.9.3 are 'SSLv23' or 'TLSV1'
@@ -101,11 +101,30 @@ module Katello
101
101
  Rails.logger.error("Pool #{pool.id} is missing its subscription id.")
102
102
  end
103
103
  end
104
- all_products.flatten!
104
+ all_products.uniq.flatten
105
105
  end
106
106
 
107
- def available_content
108
- self.products ? self.products.map(&:available_content).flatten.uniq { |product| product.content.id } : []
107
+ def all_products
108
+ Katello::Product.joins(:subscriptions => :pools).where(:organization_id => organization.id).enabled.uniq
109
+ end
110
+
111
+ def available_content(content_access_mode_all = false, content_access_mode_env = false)
112
+ if content_access_mode_env
113
+ return [] unless environment_id && content_view_id
114
+ version = ContentViewVersion.in_environment(environment_id).where(:content_view_id => content_view_id).first
115
+ content_view_version_id = version.id
116
+ end
117
+
118
+ if content_access_mode_all
119
+ content = all_products.flat_map do |product|
120
+ product.available_content(content_view_version_id)
121
+ end
122
+ else
123
+ content = products.flat_map do |product|
124
+ product.available_content(content_view_version_id)
125
+ end
126
+ end
127
+ content.uniq
109
128
  end
110
129
 
111
130
  def valid_content_override_label?(content_label)
@@ -67,7 +67,7 @@ module Katello
67
67
  :name => name,
68
68
  :label => label,
69
69
  :url => feed_url,
70
- :feed_ca => ca,
70
+ :feed_ca => ::Katello::Repository.feed_ca_cert(feed_url),
71
71
  :feed_cert => certificate_and_key[:cert],
72
72
  :feed_key => certificate_and_key[:key],
73
73
  :content_type => katello_content_type,
@@ -173,10 +173,6 @@ module Katello
173
173
  ""
174
174
  end
175
175
  end
176
-
177
- def ca
178
- File.read(::Katello::Resources::CDN::CdnResource.ca_file)
179
- end
180
176
  end
181
177
 
182
178
  class DockerRepositoryMapper
@@ -216,7 +212,7 @@ module Katello
216
212
  :docker_upstream_name => registry["name"],
217
213
  :label => label,
218
214
  :url => feed_url,
219
- :feed_ca => ca,
215
+ :feed_ca => ::Katello::Repository.feed_ca_cert(feed_url),
220
216
  :feed_cert => product.certificate,
221
217
  :feed_key => product.key,
222
218
  :content_type => ::Katello::Repository::DOCKER_TYPE,
@@ -251,10 +247,6 @@ module Katello
251
247
  def relative_path
252
248
  ::Katello::Glue::Pulp::Repos.repo_path_from_content_path(product.organization.library, content.contentUrl)
253
249
  end
254
-
255
- def ca
256
- File.read(::Katello::Resources::CDN::CdnResource.ca_file)
257
- end
258
250
  end
259
251
  end
260
252
  end
@@ -11,7 +11,7 @@ module Katello
11
11
 
12
12
  def to_label(_options = {})
13
13
  installable = Setting[:errata_status_installable]
14
- case to_status
14
+ case status
15
15
  when NEEDED_SECURITY_ERRATA
16
16
  installable ? N_("Security errata installable") : N_("Security errata applicable")
17
17
  when NEEDED_ERRATA
@@ -26,7 +26,7 @@ module Katello
26
26
  end
27
27
 
28
28
  def to_global(_options = {})
29
- case to_status
29
+ case status
30
30
  when NEEDED_SECURITY_ERRATA
31
31
  ::HostStatus::Global::ERROR
32
32
  when NEEDED_ERRATA
@@ -95,11 +95,13 @@ module Katello
95
95
  #ca_file = '/etc/candlepin/certs/upstream/subscription.rhn.stage.redhat.com.crt'
96
96
  ca_file = nil
97
97
 
98
- capabilities = Resources::Candlepin::CandlepinPing.ping['managerCapabilities'].inject([]) do |result, element|
98
+ params = {}
99
+ params[:capabilities] = Resources::Candlepin::CandlepinPing.ping['managerCapabilities'].inject([]) do |result, element|
99
100
  result << {'name' => element}
100
101
  end
102
+ params[:facts] = {:distributor_version => 'sat-6.3'}
101
103
  Resources::Candlepin::UpstreamConsumer.update("#{url}#{upstream['uuid']}", upstream['idCert']['cert'],
102
- upstream['idCert']['key'], ca_file, :capabilities => capabilities)
104
+ upstream['idCert']['key'], ca_file, params)
103
105
  end
104
106
 
105
107
  def owner_upstream_export(upstream, zip_file_path, _options)
@@ -215,11 +215,11 @@ module Katello
215
215
  :ssl_client_key => ueber_cert[:key],
216
216
  :ssl_ca_cert => ::Cert::Certs.ca_cert
217
217
  }
218
- elsif self.try(:redhat?) && self.content_view.default?
218
+ elsif self.try(:redhat?) && self.content_view.default? && Katello::Resources::CDN::CdnResource.redhat_cdn?(url)
219
219
  importer_options = {
220
220
  :ssl_client_cert => self.product.certificate,
221
221
  :ssl_client_key => self.product.key,
222
- :ssl_ca_cert => Resources::CDN::CdnResource.ca_file_contents
222
+ :ssl_ca_cert => Katello::Repository.feed_ca_cert(url)
223
223
  }
224
224
  else
225
225
  importer_options = {
@@ -214,9 +214,10 @@ module Katello
214
214
  repositories.any?(&:url?)
215
215
  end
216
216
 
217
- def available_content
217
+ def available_content(content_view_version_id = nil)
218
218
  self.productContent.select do |content|
219
- self.repositories.subscribable.where(content_id: content.content.id).exists?
219
+ repos = self.repositories.subscribable.where(content_id: content.content.id)
220
+ repos.exists? && (content_view_version_id.nil? || repos.where(content_view_version_id: content_view_version_id.to_i).count > 0)
220
221
  end
221
222
  end
222
223
 
@@ -22,7 +22,6 @@ module Katello
22
22
  :allow_blank => false, :message => "Please select provider type from one of the following: #{TYPES.join(', ')}."}
23
23
  validate :constraint_redhat_update
24
24
  validate :only_one_rhn_provider
25
- validate :only_cdn_https
26
25
  validates_with Validators::KatelloNameFormatValidator, :attributes => :name
27
26
  validates_with Validators::KatelloUrlFormatValidator, :if => :redhat_provider?,
28
27
  :attributes => [:repository_url]
@@ -34,12 +33,6 @@ module Katello
34
33
  scope :custom, -> { where(:provider_type => CUSTOM) }
35
34
  scope :anonymous, -> { where(:provider_type => ANONYMOUS) }
36
35
 
37
- def only_cdn_https
38
- if repository_url.present? && repository_url.downcase.start_with?('https') && !repository_url.downcase.start_with?('https://cdn.redhat.com')
39
- errors.add(:base, _("HTTPS URLs are not supported, with the exception of 'cdn.redhat.com'"))
40
- end
41
- end
42
-
43
36
  def self.create_anonymous!(organization)
44
37
  create!(:name => SecureRandom.uuid, :description => nil,
45
38
  :organization => organization, :provider_type => ANONYMOUS,
@@ -207,6 +207,15 @@ module Katello
207
207
  .where("#{Katello::ContentViewVersion.table_name}.content_view_id" => views.map(&:id))
208
208
  end
209
209
 
210
+ def self.feed_ca_cert(url)
211
+ file = feed_ca_file(url)
212
+ File.read(file) if file
213
+ end
214
+
215
+ def self.feed_ca_file(url)
216
+ ::Katello::Resources::CDN::CdnResource.ca_file if ::Katello::Resources::CDN::CdnResource.redhat_cdn?(url)
217
+ end
218
+
210
219
  def archive?
211
220
  self.environment.nil?
212
221
  end
@@ -121,8 +121,28 @@ module Katello
121
121
  Katello::Product.joins(:subscriptions => :pools).where("#{Katello::Pool.table_name}.cp_id" => pool_ids).enabled.uniq
122
122
  end
123
123
 
124
- def available_product_content
125
- products.flat_map(&:available_content)
124
+ def all_products
125
+ org_id = ::Katello::Host::SubscriptionFacet.find_by_uuid(self.uuid).host.organization.id
126
+ Katello::Product.joins(:subscriptions => :pools).where(:organization_id => org_id).enabled.uniq
127
+ end
128
+
129
+ def available_product_content(content_access_mode_all = false, content_access_mode_env = false)
130
+ if content_access_mode_env
131
+ host = ::Katello::Host::ContentFacet.find_by_uuid(self.uuid)
132
+ return [] unless host.lifecycle_environment_id && host.content_view_id
133
+ version = ContentViewVersion.in_environment(host.lifecycle_environment_id).where(:content_view_id => host.content_view_id).first
134
+ content_view_version_id = version.id
135
+ end
136
+ if content_access_mode_all
137
+ content = all_products.flat_map do |product|
138
+ product.available_content(content_view_version_id)
139
+ end
140
+ else
141
+ content = products.flat_map do |product|
142
+ product.available_content(content_view_version_id)
143
+ end
144
+ end
145
+ content.uniq
126
146
  end
127
147
 
128
148
  def compliance_reasons
@@ -8,7 +8,7 @@
8
8
  {{ syncTask.progressbar.value || 0 | number: 0 }}%
9
9
  <a href="<%= @task_search_url %>" target="_self">
10
10
  <div ng-class="{ active: isTaskInProgress(syncTask) }" class="progress progress-striped">
11
- <span progressbar
11
+ <span uib-progressbar
12
12
  animate="false"
13
13
  value="syncTask.progressbar.value || 0"
14
14
  type="{{ progressbarType(syncTask) }}"></span>
@@ -2,6 +2,7 @@ attributes :id, :uuid
2
2
  attributes :content_view_id, :content_view_name
3
3
  attributes :lifecycle_environment_id, :lifecycle_environment_name
4
4
  attributes :content_source_id, :content_source_name
5
+ attributes :kickstart_repository_id
5
6
 
6
7
  child :content_view => :content_view do
7
8
  attributes :id, :name
@@ -1,15 +1,17 @@
1
- node :security do |presenter|
2
- presenter.relation.security.count
1
+ totals = @object.relation.group(:errata_type).count.with_indifferent_access
2
+
3
+ node :security do |_presenter|
4
+ totals[:security]
3
5
  end
4
6
 
5
- node :bugfix do |presenter|
6
- presenter.relation.bugfix.count
7
+ node :bugfix do |_presenter|
8
+ totals[:bugfix]
7
9
  end
8
10
 
9
- node :enhancement do |presenter|
10
- presenter.relation.enhancement.count
11
+ node :enhancement do |_presenter|
12
+ totals[:enhancement]
11
13
  end
12
14
 
13
- node :total do |presenter|
14
- presenter.relation.count
15
+ node :total do |_presenter|
16
+ totals.values.inject(:+)
15
17
  end
@@ -1,3 +1,3 @@
1
1
  object @hostgroup
2
2
  extends 'api/v2/hostgroups/show'
3
- attributes :content_source_id, :content_source_name, :content_view_id, :content_view_name, :lifecycle_environment_id, :lifecycle_environment_name
3
+ attributes :content_source_id, :content_source_name, :content_view_id, :content_view_name, :lifecycle_environment_id, :lifecycle_environment_name, :kickstart_repository_id
@@ -3,7 +3,12 @@ if Katello.with_remote_execution?
3
3
  JobTemplate.without_auditing do
4
4
  Dir[File.join("#{Katello::Engine.root}/app/views/foreman/job_templates/**/*.erb")].each do |template|
5
5
  sync = !Rails.env.test? && Setting[:remote_execution_sync_templates]
6
- JobTemplate.import!(File.read(template), :default => true, :locked => true, :update => sync)
6
+ # import! was renamed to import_raw! around 1.3.1
7
+ if JobTemplate.respond_to?('import_raw!')
8
+ JobTemplate.import_raw!(File.read(template), :default => true, :locked => true, :update => sync)
9
+ else
10
+ JobTemplate.import!(File.read(template), :default => true, :locked => true, :update => sync)
11
+ end
7
12
  end
8
13
  end
9
14
  end
@@ -16,7 +16,7 @@
16
16
  angular.module('Bastion.activation-keys').controller('ActivationKeyRepositorySetsController',
17
17
  ['$scope', 'translate', 'Nutupane', 'ActivationKey', 'ContentOverrideHelper', 'GlobalNotification', 'CurrentOrganization',
18
18
  function ($scope, translate, Nutupane, ActivationKey, ContentOverrideHelper, GlobalNotification, CurrentOrganization) {
19
- var nutupane, params, saveContentOverride, success, error;
19
+ var params, saveContentOverride, success, error;
20
20
 
21
21
  params = {
22
22
  id: $scope.$stateParams.activationKeyId,
@@ -27,13 +27,23 @@ angular.module('Bastion.activation-keys').controller('ActivationKeyRepositorySet
27
27
  };
28
28
 
29
29
  $scope.controllerName = 'katello_products';
30
- nutupane = new Nutupane(ActivationKey, params, 'repositorySets');
31
- $scope.table = nutupane.table;
30
+ $scope.nutupane = new Nutupane(ActivationKey, params, 'repositorySets');
31
+ $scope.table = $scope.nutupane.table;
32
+
33
+ $scope.contentAccessModes = {
34
+ contentAccessModeAll: false,
35
+ contentAccessModeEnv: false
36
+ };
37
+ $scope.toggleFilters = function () {
38
+ $scope.nutupane.table.params['content_access_mode_env'] = $scope.contentAccessModes.contentAccessModeEnv;
39
+ $scope.nutupane.table.params['content_access_mode_all'] = $scope.contentAccessModes.contentAccessModeAll;
40
+ $scope.nutupane.refresh();
41
+ };
32
42
 
33
43
  success = function () {
34
44
  $scope.table.working = false;
35
45
  GlobalNotification.setSuccessMessage(translate('Repository Sets settings saved successfully.'));
36
- nutupane.refresh();
46
+ $scope.nutupane.refresh();
37
47
  };
38
48
 
39
49
  error = function (response) {
@@ -5,17 +5,8 @@
5
5
  <h2>{{ activationKey.name }}</h2>
6
6
  </header>
7
7
 
8
- <div data-block="item-actions">
9
- <div class="btn-group" uib-dropdown keyboard-nav bst-feature-flag="custom_products">
10
- <button type="button" class="btn btn-default" uib-dropdown-toggle>
11
- <span translate>Select Action</span>
12
- </button>
13
-
14
- <button type="button" class="btn btn-default" uib-dropdown-toggle>
15
- <span class="caret"></span>
16
- <span class="sr-only" translate>Toggle Dropdown</span>
17
- </button>
18
-
8
+ <div data-block="item-actions" bst-feature-flag="custom_products">
9
+ <span select-action-dropdown>
19
10
  <ul class="dropdown-menu dropdown-menu-right" uib-dropdown-menu role="menu">
20
11
  <li role="menuitem" ng-hide="denied('create_activation_key')">
21
12
  <a ui-sref="activation-key.copy" translate>
@@ -36,7 +27,7 @@
36
27
  <div data-block="modal-header" translate>Remove Activation Key "{{ activationKey.name }}"?</div>
37
28
  <div data-block="modal-body" translate>Are you sure you want to remove Activation Key "{{ activationKey.name }}"?</div>
38
29
  </div>
39
- </div>
30
+ </span>
40
31
  </div>
41
32
 
42
33
  <nav data-block="navigation">
@@ -16,17 +16,20 @@
16
16
  ng-model="repositorySetFilter"/>
17
17
  </div>
18
18
 
19
- <div data-block="list-actions">
20
- <div class="btn-group" uib-dropdown keyboard-nav>
21
-
22
- <button class="btn btn-default" type="button" uib-dropdown-toggle translate>
23
- Select Action
24
- </button>
19
+ <div data-block="filters">
20
+ <label class="checkbox-inline" title="{{ 'Show all Repository Sets in Organization' | translate }}">
21
+ <input type="checkbox" ng-model="contentAccessModes.contentAccessModeAll" ng-change="toggleFilters()"/>
22
+ <span translate>Show All</span>
23
+ </label>
24
+ <label class="checkbox-inline" title="{{ 'Limit Repository Sets to only those available in this Activation Key\'s Lifecycle Environment' | translate }}">
25
+ <input type="checkbox" ng-model="contentAccessModes.contentAccessModeEnv" ng-change="toggleFilters()"/>
26
+ <span translate>Limit to Environment</span>
27
+ </label>
28
+ </div>
25
29
 
26
- <button type="button" class="btn btn-default" uib-dropdown-toggle>
27
- <span class="caret"></span>
28
- </button>
29
30
 
31
+ <div data-block="list-actions">
32
+ <div class="btn-group" select-action-dropdown>
30
33
  <ul class="dropdown-menu-right" uib-dropdown-menu role="menu" aria-labelledby="split-button">
31
34
  <li role="menuitem" ng-show="permitted('edit_activation_keys', activationKey)" ng-class="{disabled: table.numSelected === 0}">
32
35
  <a ng-click="overrideToEnabled()" disable-link="table.numSelected === 0" translate>
@@ -82,4 +85,4 @@
82
85
  </tbody>
83
86
  </table>
84
87
  </div>
85
- </div>
88
+ </div>
@@ -9,7 +9,7 @@
9
9
  * Provides common functionality in handling Katello/Foreman API Errors.
10
10
  */
11
11
  function ApiErrorHandler(translate, GlobalNotification) {
12
- this.handleGETRequestErrors = function (response, $scope) {
12
+ function handleError(response, $scope, defaultErrorMessage) {
13
13
  var hasScopeErrorMessages = $scope && $scope.hasOwnProperty('errorMessages');
14
14
 
15
15
  if (response.hasOwnProperty('data') && response.data.hasOwnProperty('errors')) {
@@ -22,20 +22,28 @@
22
22
  }
23
23
  } else {
24
24
  if (hasScopeErrorMessages) {
25
- $scope.errorMessages = [translate('Something went wrong when retrieving the resource.')];
25
+ $scope.errorMessages = [defaultErrorMessage];
26
26
  } else {
27
- GlobalNotification.setErrorMessage(translate('Something went wrong when retrieving the resource.'));
27
+ GlobalNotification.setErrorMessage(defaultErrorMessage);
28
28
  }
29
29
  }
30
30
 
31
31
  if ($scope && $scope.hasOwnProperty('panel')) {
32
32
  $scope.panel.error = true;
33
33
  }
34
+ }
35
+
36
+ this.handleGETRequestErrors = function (response, $scope) {
37
+ var defaultErrorMessage = translate('Something went wrong when retrieving the resource.');
38
+ handleError(response, $scope, defaultErrorMessage);
39
+ };
40
+
41
+ this.handlePUTRequestErrors = function (response, $scope) {
42
+ var defaultErrorMessage = translate('Something went wrong when saving the resource.');
43
+ handleError(response, $scope, defaultErrorMessage);
34
44
  };
35
45
  }
36
46
 
37
47
  angular.module('Bastion.common').service('ApiErrorHandler', ApiErrorHandler);
38
-
39
48
  ApiErrorHandler.$inject = ['translate', 'GlobalNotification'];
40
-
41
49
  })();
@@ -0,0 +1,45 @@
1
+ (function () {
2
+ 'use strict';
3
+
4
+ /**
5
+ * @ngdoc directive
6
+ * @name Bastion.common.directive:selectActionDropdown
7
+ *
8
+ * @description
9
+ * Used to create a dropdown menu with a list of actions in it and the words "Select Action" on the button.
10
+ *
11
+ * Necessary because of https://github.com/angular-ui/bootstrap/issues/5841
12
+ *
13
+ * @example
14
+ * <span select-action-dropdown>
15
+ * <ul>...</ul>
16
+ * </span>
17
+ */
18
+ function selectActionDropdown() {
19
+ return {
20
+ restrict: 'AE',
21
+ transclude: true,
22
+ scope: true,
23
+ templateUrl: 'common/views/select-action-dropdown.html',
24
+ compile: function (tElement, tAttribute, transclude) {
25
+ return function (scope, element) {
26
+ scope.status = {
27
+ isOpen: false
28
+ };
29
+
30
+ scope.toggleDropdown = function (event) {
31
+ event.preventDefault();
32
+ event.stopPropagation();
33
+ scope.status.isOpen = !scope.status.isOpen;
34
+ };
35
+
36
+ transclude(scope, function(clone) {
37
+ element.find('.btn-group').append(clone);
38
+ });
39
+ };
40
+ }
41
+ };
42
+ }
43
+
44
+ angular.module('Bastion.common').directive('selectActionDropdown', selectActionDropdown);
45
+ })();
@@ -0,0 +1,10 @@
1
+ <div class="btn-group" uib-dropdown is-open="status.isOpen" keyboard-nav>
2
+ <button type="button" class="btn btn-default" ng-click="toggleDropdown($event)">
3
+ <span translate>Select Action</span>
4
+ </button>
5
+
6
+ <button type="button" class="btn btn-default" uib-dropdown-toggle>
7
+ <span class="caret"></span>
8
+ <span class="sr-only" translate>Toggle Dropdown</span>
9
+ </button>
10
+ </div>
@@ -16,7 +16,7 @@
16
16
  angular.module('Bastion.content-hosts').controller('ContentHostRepositorySetsController',
17
17
  ['$scope', 'translate', 'Nutupane', 'HostSubscription', 'ContentOverrideHelper', 'GlobalNotification', 'CurrentOrganization',
18
18
  function ($scope, translate, Nutupane, HostSubscription, ContentOverrideHelper, GlobalNotification, CurrentOrganization) {
19
- var nutupane, params, saveContentOverride, success, error;
19
+ var params, saveContentOverride, success, error;
20
20
 
21
21
  params = {
22
22
  id: $scope.$stateParams.hostId,
@@ -27,13 +27,23 @@ angular.module('Bastion.content-hosts').controller('ContentHostRepositorySetsCon
27
27
  };
28
28
 
29
29
  $scope.controllerName = 'katello_products';
30
- nutupane = new Nutupane(HostSubscription, params, 'repositorySets');
31
- $scope.table = nutupane.table;
30
+ $scope.nutupane = new Nutupane(HostSubscription, params, 'repositorySets');
31
+ $scope.table = $scope.nutupane.table;
32
+
33
+ $scope.contentAccessModes = {
34
+ contentAccessModeAll: false,
35
+ contentAccessModeEnv: false
36
+ };
37
+ $scope.toggleFilters = function () {
38
+ $scope.nutupane.table.params['content_access_mode_all'] = $scope.contentAccessModes.contentAccessModeAll;
39
+ $scope.nutupane.table.params['content_access_mode_env'] = $scope.contentAccessModes.contentAccessModeEnv;
40
+ $scope.nutupane.refresh();
41
+ };
32
42
 
33
43
  success = function () {
34
44
  $scope.table.working = false;
35
45
  GlobalNotification.setSuccessMessage(translate('Repository Sets settings saved successfully.'));
36
- nutupane.refresh();
46
+ $scope.nutupane.refresh();
37
47
  };
38
48
 
39
49
  error = function (response) {
@@ -23,17 +23,19 @@
23
23
  ng-model="repositorySetFilter"/>
24
24
  </div>
25
25
 
26
- <div data-block="list-actions">
27
- <div class="btn-group" uib-dropdown keyboard-nav>
28
-
29
- <button class="btn btn-default" type="button" uib-dropdown-toggle>
30
- <span translate>Select Action</span>
31
- </button>
32
-
33
- <button type="button" class="btn btn-default" uib-dropdown-toggle>
34
- <span class="caret"></span>
35
- </button>
26
+ <div data-block="filters">
27
+ <label class="checkbox-inline" title="{{ 'Show all Repository Sets in Organization' | translate }}">
28
+ <input type="checkbox" ng-model="contentAccessModes.contentAccessModeAll" ng-change="toggleFilters()"/>
29
+ <span translate>Show All</span>
30
+ </label>
31
+ <label class="checkbox-inline" title="{{ 'Limit Repository Sets to only those available in this Host\'s Lifecycle Environment' | translate }}">
32
+ <input type="checkbox" ng-model="contentAccessModes.contentAccessModeEnv" ng-change="toggleFilters()"/>
33
+ <span translate>Limit to Environment</span>
34
+ </label>
35
+ </div>
36
36
 
37
+ <div data-block="list-actions">
38
+ <span select-action-dropdown>
37
39
  <ul class="dropdown-menu-right" uib-dropdown-menu role="menu" aria-labelledby="split-button">
38
40
  <li role="menuitem" ng-show="permitted('edit_activation_keys', activationKey)" ng-class="{disabled: table.numSelected === 0}">
39
41
  <a ng-click="overrideToEnabled()" disable-link="table.numSelected === 0" translate>
@@ -53,7 +55,7 @@
53
55
  </a>
54
56
  </li>
55
57
  </ul>
56
- </div>
58
+ </span>
57
59
  </div>
58
60
 
59
61
  <span data-block="no-rows-message" translate>
@@ -90,4 +92,4 @@
90
92
  </table>
91
93
  </div>
92
94
  </div>
93
- </div>
95
+ </div>
@@ -12,15 +12,7 @@
12
12
  <span translate>Register Content Host</span>
13
13
  </button>
14
14
 
15
- <div class="btn-group" uib-dropdown keyboard-nav>
16
- <button type="button" class="btn btn-default" uib-dropdown-toggle>
17
- <span translate>Select Action</span>
18
- </button>
19
-
20
- <button type="button" class="btn btn-default" uib-dropdown-toggle>
21
- <span class="caret"></span>
22
- </button>
23
-
15
+ <span select-action-dropdown>
24
16
  <ul class="dropdown-menu dropdown-menu-right" uib-dropdown-menu role="menu" aria-labelledby="split-button">
25
17
  <li role="menuitem" ng-show="permitted('edit_hosts')" ng-class="{disabled: table.numSelected === 0}">
26
18
  <a ng-click="openHostCollectionsModal()" disable-link="table.numSelected === 0" translate>Change Host Collections</a>
@@ -49,7 +41,7 @@
49
41
  <span bst-modal="performDestroyHosts()" template-url="content-hosts/bulk/views/content-hosts-bulk-destroy-modal.html"></span>
50
42
  </li>
51
43
  </ul>
52
- </div>
44
+ </span>
53
45
  </div>
54
46
 
55
47
  <span data-block="no-rows-message" translate>
@@ -13,38 +13,30 @@
13
13
  </div>
14
14
 
15
15
  <nav data-block="item-actions">
16
- <div class="btn-group" uib-dropdown keyboard-nav bst-feature-flag="custom_products">
17
- <button type="button" class="btn btn-default" uib-dropdown-toggle>
18
- <span translate>Select Action</span>
19
- </button>
20
-
21
- <button type="button" class="btn btn-default" uib-dropdown-toggle>
22
- <span class="caret"></span>
23
- <span class="sr-only" translate>Toggle Dropdown</span>
24
- </button>
25
-
26
- <ul class="dropdown-menu dropdown-menu-right" uib-dropdown-menu role="menu">
27
- <li role="menuitem" ng-hide="denied('publish_content_views', contentView)">
28
- <a ui-sref="content-view.publish">
29
- <span translate>Publish New Version</span>
30
- </a>
31
- </li>
32
-
33
- <li role="menuitem" ng-hide="denied('publish_content_views', contentView)">
34
- <a ui-sref="content-view.copy">
35
- <span translate>Copy Content View</span>
36
- </a>
37
- </li>
38
-
39
- <li class="divider" ng-hide="denied('destroy_content_views', contentView)"></li>
40
-
41
- <li role="menuitem" ng-hide="denied('destroy_content_views', contentView)">
42
- <a ui-sref="content-view.deletion">
43
- <span translate>Remove Content View</span>
44
- </a>
45
- </li>
46
- </ul>
47
- </div>
16
+ <button type="button" class="btn btn-primary" ng-hide="denied('publish_content_views', contentView)"
17
+ ui-sref="content-view.publish">
18
+ <span translate>Publish New Version</span>
19
+ </button>
20
+
21
+ <span bst-feature-flag="custom_products">
22
+ <span select-action-dropdown>
23
+ <ul class="dropdown-menu dropdown-menu-right" uib-dropdown-menu role="menu">
24
+ <li role="menuitem" ng-hide="denied('publish_content_views', contentView)">
25
+ <a ui-sref="content-view.copy">
26
+ <span translate>Copy Content View</span>
27
+ </a>
28
+ </li>
29
+
30
+ <li class="divider" ng-hide="denied('destroy_content_views', contentView)"></li>
31
+
32
+ <li role="menuitem" ng-hide="denied('destroy_content_views', contentView)">
33
+ <a ui-sref="content-view.deletion">
34
+ <span translate>Remove Content View</span>
35
+ </a>
36
+ </li>
37
+ </ul>
38
+ </span>
39
+ </span>
48
40
  </nav>
49
41
 
50
42
  <nav data-block="navigation">
@@ -5,14 +5,14 @@
5
5
  <dl class="dl-horizontal dl-horizontal-left">
6
6
  <dt translate>Product</dt>
7
7
  <dd>
8
- <a ui-sref="products.details.info({productId: tag.product.id})">
8
+ <a ui-sref="product.info({productId: tag.product.id})">
9
9
  {{ tag.product.name }}
10
10
  </a>
11
11
  </dd>
12
12
 
13
13
  <dt translate>Repository</dt>
14
14
  <dd>
15
- <a ui-sref="products.details.repositories.manage-content.docker-manifests({productId: tag.product.id, repositoryId: tag.repository.id})">
15
+ <a ui-sref="product.repository.manage-content.docker-manifests({productId: tag.product.id, repositoryId: tag.repository.id})">
16
16
  {{ tag.repository.name }}
17
17
  </a>
18
18
  </dd>
@@ -6,16 +6,7 @@
6
6
  </div>
7
7
 
8
8
  <div data-block="item-actions">
9
- <div class="btn-group" uib-dropdown keyboard-nav bst-feature-flag="custom_products">
10
- <button type="button" class="btn btn-default" uib-dropdown-toggle>
11
- <span translate>Select Action</span>
12
- </button>
13
-
14
- <button type="button" type="button" class="btn btn-default" uib-dropdown-toggle>
15
- <span class="caret"></span>
16
- <span class="sr-only" translate>Toggle Dropdown</span>
17
- </button>
18
-
9
+ <span select-action-dropdown>
19
10
  <ul class="dropdown-menu dropdown-menu-right" uib-dropdown-menu role="menu">
20
11
  <li role="menuitem" ng-hide="denied('create_host_collections')">
21
12
  <a ui-sref="host-collection.copy" translate>
@@ -36,7 +27,7 @@
36
27
  <div data-block="modal-header" translate>Remove Host Collection "{{ hostCollection.name }}"?</div>
37
28
  <div data-block="modal-body" translate>Are you sure you want to remove Host Collection "{{ hostCollection.name }}"?</div>
38
29
  </div>
39
- </div>
30
+ </span>
40
31
  </div>
41
32
 
42
33
  <nav data-block="navigation" ng-hide="isState('host-collection.copy')">
@@ -51,7 +51,7 @@
51
51
  </a>
52
52
  </td>
53
53
  <td bst-table-cell>
54
- <a ui-sref="products.details.repositories.index({productId: repository.product.id})">
54
+ <a ui-sref="product.repositories({productId: repository.product.id})">
55
55
  {{ repository.product.name }}
56
56
  </a>
57
57
  </td>
@@ -5,17 +5,8 @@
5
5
  <h2 translate>{{ repository.name }}</h2>
6
6
  </header>
7
7
 
8
- <div data-block="item-actions">
9
- <div class="btn-group" uib-dropdown keyboard-nav bst-feature-flag="custom_products">
10
- <button type="button" class="btn btn-default" uib-dropdown-toggle>
11
- <span translate>Select Action</span>
12
- </button>
13
-
14
- <button type="button" class="btn btn-default" uib-dropdown-toggle>
15
- <span class="caret"></span>
16
- <span class="sr-only" translate>Toggle Dropdown</span>
17
- </button>
18
-
8
+ <div data-block="item-actions" bst-feature-flag="custom_products">
9
+ <span select-action-dropdown>
19
10
  <ul class="dropdown-menu-right" uib-dropdown-menu role="menu">
20
11
  <li role="menuitem" ng-hide="hideSyncButton(repository, false)" ng-class="{disabled: disableSyncLink()}">
21
12
  <a ng-click="syncRepository(repository)" disable-link="disableSyncLink()" translate>
@@ -92,7 +83,7 @@
92
83
  <div data-block="modal-header" translate>Remove Repository "{{ repository.name }}"?</div>
93
84
  <div data-block="modal-body" translate>Are you sure you want to remove repository "{{ repository.name }}"?</div>
94
85
  </div>
95
- </div>
86
+ </span>
96
87
  </div>
97
88
 
98
89
  <div data-block="content">
@@ -5,16 +5,8 @@
5
5
  <h2 translate>{{ product.name }}</h2>
6
6
  </header>
7
7
 
8
- <nav data-block="item-actions">
9
- <div class="btn-group" uib-dropdown keyboard-nav bst-feature-flag="custom_products">
10
- <button type="button" class="btn btn-default" uib-dropdown-toggle>
11
- <span translate>Select Action</span>
12
- </button>
13
- <button type="button" class="btn btn-default" uib-dropdown-toggle>
14
- <span class="caret"></span>
15
- <span class="sr-only" translate>Toggle Dropdown</span>
16
- </button>
17
-
8
+ <nav data-block="item-actions" bst-feature-flag="custom_products">
9
+ <span select-action-dropdown>
18
10
  <ul class="dropdown-menu dropdown-menu-right" uib-dropdown-menu role="menu">
19
11
  <li role="menuitem" ng-hide="denied('sync_products', product)">
20
12
  <a ng-click="syncProduct()">
@@ -58,7 +50,7 @@
58
50
  </span>
59
51
  </li>
60
52
  </ul>
61
- </div>
53
+ </span>
62
54
 
63
55
  <div bst-modal="removeProduct(product)" model="product">
64
56
  <div data-block="modal-header" translate>Remove Product "{{ product.name }}"?</div>
@@ -21,16 +21,7 @@
21
21
  <span translate>Repo Discovery</span>
22
22
  </button>
23
23
 
24
- <div class="btn-group" uib-dropdown keyboard-nav>
25
- <button type="button" class="btn btn-default" uib-dropdown-toggle>
26
- <span translate>Select Action</span>
27
- </button>
28
-
29
- <button type="button" class="btn btn-default" uib-dropdown-toggle>
30
- <span class="caret"></span>
31
- <span class="sr-only" translate>Toggle Dropdown</span>
32
- </button>
33
-
24
+ <span select-action-dropdown>
34
25
  <ul class="dropdown-menu-right" uib-dropdown-menu role="menu" aria-labelledby="split-button">
35
26
  <li role="menuitem" ng-class="{disabled: table.numSelected === 0}">
36
27
  <a ng-click="syncProducts()" ng-show="permitted('sync_products')" disable-link="table.numSelected === 0" translate>
@@ -71,7 +62,7 @@
71
62
  </div>
72
63
  </li>
73
64
  </ul>
74
- </div>
65
+ </span>
75
66
  </div>
76
67
 
77
68
  <span data-block="no-rows-message" translate>
@@ -13,17 +13,8 @@
13
13
  </div>
14
14
  </div>
15
15
 
16
- <nav data-block="item-actions">
17
- <div class="btn-group" uib-dropdown keyboard-nav bst-feature-flag="custom_products">
18
- <button type="button" class="btn btn-default" uib-dropdown-toggle>
19
- <span translate>Select Action</span>
20
- </button>
21
-
22
- <button type="button" class="btn btn-default" uib-dropdown-toggle>
23
- <span class="caret"></span>
24
- <span class="sr-only" translate>Toggle Dropdown</span>
25
- </button>
26
-
16
+ <nav data-block="item-actions" bst-feature-flag="custom_products">
17
+ <span select-action-dropdown>
27
18
  <ul class="dropdown-menu dropdown-menu-right" uib-dropdown-menu role="menu">
28
19
  <li role="menuitem" ng-hide="denied('sync_products')">
29
20
  <a ng-click="runSyncPlan()">
@@ -44,7 +35,7 @@
44
35
  <div data-block="modal-header" translate>Remove Sync Plan "{{ syncPlan.name }}"?</div>
45
36
  <div data-block="modal-body" translate>Are you sure you want to remove Sync Plan "{{ syncPlan.name }}"?</div>
46
37
  </div>
47
- </div>
38
+ </span>
48
39
  </nav>
49
40
 
50
41
  <nav data-block="navigation">
@@ -63,7 +63,7 @@
63
63
  <tbody>
64
64
  <tr bst-table-row ng-repeat="product in table.rows" row-select="product">
65
65
  <td bst-table-cell>
66
- <a ui-sref="products.details.info({productId: product.id})">
66
+ <a ui-sref="product.info({productId: product.id})">
67
67
  {{ product.name }}
68
68
  </a>
69
69
  </td>
@@ -244,13 +244,13 @@ Foreman::Plugin.register :katello do
244
244
 
245
245
  add_controller_action_scope(HostsController, :index) do |base_scope|
246
246
  base_scope
247
- .preload(:content_view, :lifecycle_environment, :subscription_facet, :applicable_errata)
248
- .preload(content_facet: [:bound_repositories, :applicable_errata, :content_view, :lifecycle_environment])
247
+ .preload(:content_view, :lifecycle_environment, :subscription_facet)
248
+ .preload(content_facet: [:bound_repositories, :content_view, :lifecycle_environment])
249
249
  end
250
250
 
251
251
  add_controller_action_scope(Api::V2::HostsController, :index) do |base_scope|
252
252
  base_scope
253
- .preload(:content_view, :lifecycle_environment, :subscription_facet, :applicable_errata)
254
- .preload(content_facet: [:bound_repositories, :applicable_errata, :content_view, :lifecycle_environment])
253
+ .preload(:content_view, :lifecycle_environment, :subscription_facet)
254
+ .preload(content_facet: [:bound_repositories, :content_view, :lifecycle_environment])
255
255
  end
256
256
  end
@@ -1,3 +1,3 @@
1
1
  module Katello
2
- VERSION = "3.4.0.2".freeze
2
+ VERSION = "3.4.1".freeze
3
3
  end
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: 3.4.0.2
4
+ version: 3.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: 2017-05-26 00:00:00.000000000 Z
11
+ date: 2017-06-13 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rails
@@ -1435,7 +1435,9 @@ files:
1435
1435
  - engines/bastion_katello/app/assets/javascripts/bastion_katello/capsules/capsules.module.js
1436
1436
  - engines/bastion_katello/app/assets/javascripts/bastion_katello/common/api-error-handler.service.js
1437
1437
  - engines/bastion_katello/app/assets/javascripts/bastion_katello/common/common.module.js
1438
+ - engines/bastion_katello/app/assets/javascripts/bastion_katello/common/select-action-dropdown.directive.js
1438
1439
  - engines/bastion_katello/app/assets/javascripts/bastion_katello/common/views/registration.html
1440
+ - engines/bastion_katello/app/assets/javascripts/bastion_katello/common/views/select-action-dropdown.html
1439
1441
  - engines/bastion_katello/app/assets/javascripts/bastion_katello/common/views/subscription-add-or-remove.html
1440
1442
  - engines/bastion_katello/app/assets/javascripts/bastion_katello/content-hosts/bulk/content-hosts-bulk-environment-modal.controller.js
1441
1443
  - engines/bastion_katello/app/assets/javascripts/bastion_katello/content-hosts/bulk/content-hosts-bulk-errata-modal.controller.js