-
Notifications
You must be signed in to change notification settings - Fork 287
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Fixes #19954 - Add CSV export on content host index #6814
Conversation
@tbrisker, thanks for your PR! By analyzing the history of the files in this pull request, we identified @waldenraines, @ehelms and @jlsherrill to be potential reviewers. |
'applicable_errata.enhancement.count', 'applicable_rpms.count', | ||
:operatingsystem, :lifecycle_environment, :content_view, | ||
'subscription_facet.registered_at', 'subscription_facet.last_checkin'], | ||
['Name', 'Subscription Status', 'Installable Updates - Security', 'Installable Updates - Bug Fixes', 'Installable Updates - Enhancements', 'Installable Updates - Package Count', 'OS', 'Environment', 'Content View', 'Registered', 'Last Checkin']) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Line is too long. [261/200]
'applicable_errata.security.count', 'applicable_errata.bugfix.count', | ||
'applicable_errata.enhancement.count', 'applicable_rpms.count', | ||
:operatingsystem, :lifecycle_environment, :content_view, | ||
'subscription_facet.registered_at', 'subscription_facet.last_checkin'], |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Align the elements of an array literal if they span more than one line.
csv_response(@hosts, [:name, :subscription_status_label, | ||
'applicable_errata.security.count', 'applicable_errata.bugfix.count', | ||
'applicable_errata.enhancement.count', 'applicable_rpms.count', | ||
:operatingsystem, :lifecycle_environment, :content_view, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Align the elements of an array literal if they span more than one line.
.preload(:subscription_status_object, :content_facet, :subscription_facet) | ||
csv_response(@hosts, [:name, :subscription_status_label, | ||
'applicable_errata.security.count', 'applicable_errata.bugfix.count', | ||
'applicable_errata.enhancement.count', 'applicable_rpms.count', |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Align the elements of an array literal if they span more than one line.
@hosts = resource_base_with_search.where(organization_id: params[:organization_id]) | ||
.preload(:subscription_status_object, :content_facet, :subscription_facet) | ||
csv_response(@hosts, [:name, :subscription_status_label, | ||
'applicable_errata.security.count', 'applicable_errata.bugfix.count', |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Align the elements of an array literal if they span more than one line.
format.csv do | ||
@hosts = resource_base_with_search.where(organization_id: params[:organization_id]) | ||
.preload(:subscription_status_object, :content_facet, :subscription_facet) | ||
csv_response(@hosts, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why not use a view layer (i.e. hosts.csv.erb) ? More complex model-formatting logic could go in a decorator or presenter. It seems like bad practice to bloat the controller for csv functionality.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There is no view, the data is streamed directly one row at a time by the CSV exporter to the client. Since reports can sometimes be very large, we don't want to block the download until they are generated completely.
This is only complex because of the amount of columns and relations this table has, other tables are much simpler (you can see some examples in foreman core).
This works after updating the foreman controller/csv_responder.rb file following similar changes in the app/services/csv_exporter.rb to accept the third parameter. Could you verify this? |
@@ -23,6 +26,35 @@ def puppet_environment_for_content_view | |||
cvpe = Katello::ContentViewPuppetEnvironment.where(:environment_id => environment, :content_view_version_id => version).first | |||
render :json => cvpe.nil? ? nil : {:name => cvpe.puppet_environment.name, :id => cvpe.puppet_environment.id} | |||
end | |||
|
|||
def content_hosts |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think having a separate endpoint for 'content host' information is not ideal. We've worked on unifying these concepts at the api and model layer and I think we should continue work towards that. This would mean that the list of attributes for csv would need to be pluggable, but i think thats a better route and could be used for our extensions of hostgroup as well.
@sjha4 Thanks for catching that, I've opened theforeman/foreman#4578 to fix the issue. |
Pushed with a bit of improvement to the preloaded tables; still having an issue of having to count applicable errata by type per host, not sure if there is anything that can be done about that though. |
I'm suggesting that the same endpoint be used and return all the same information no matter which page they are on. When katello is installed, more information is returned on both pages. This could involve: a) using the 'rails' way of alias method chaining the 'csv_columns' method to add things to the normal host controller array. a) is quite trivial so i'm fine with that in the shorter term, but i do think its a better solution than creating two different host csv lists. The UI being split into two (Hosts and content hosts) is a bug not a feature, so I'd like to limit it as much as possible |
@jlsherrill There are two problems with your suggested approach:
|
I see, so the intent is to just let the user download the information in the table rather than download information about 'hosts'. If thats the case I'm okay with it! |
Yes, currently for the hosts api we're still having to do an N+1 query. I don't know of a way in rails to do this as there is no attribute on the model that can represent the various counts. The only solution I know of to eliminate them completely would be to cache the values on the objects themselves which i think is becoming more and more of a necessity. |
Current test failure is just due to permissions, your new route needs to be added here: https://github.com/Katello/katello/blob/master/lib/katello/permissions/host_permissions.rb#L36 I opened http://projects.theforeman.org/issues/20019 to pull the errata counts into the various objects as a cache. |
@jlsherrill thanks, added the missing permission |
assert_equal "attachment; filename=\"hosts-#{Date.today}.csv\"", response.headers["Content-Disposition"] | ||
buf = response.stream.instance_variable_get(:@buf) | ||
assert buf.is_a? Enumerator | ||
assert_equal Katello::Concerns::HostsControllerExtensions::CSV_HEADER.join(',')+"\n", buf.next |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Surrounding space missing for operator +.
'applicable_errata.bugfix.size', 'applicable_errata.enhancement.size', | ||
'applicable_rpms.size', :operatingsystem, :lifecycle_environment, :content_view, | ||
'subscription_facet.registered_at', 'subscription_facet.last_checkin'] | ||
CSV_HEADER= ['Name', 'Subscription Status', 'Installable Updates - Security', |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Surrounding space missing for operator =.
Freeze mutable objects assigned to constants.
@@ -3,7 +3,17 @@ module Concerns | |||
module HostsControllerExtensions | |||
extend ActiveSupport::Concern | |||
include ForemanTasks::Triggers | |||
CSV_FIELDS = [:name, :subscription_status_label, 'applicable_errata.security.size', |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Freeze mutable objects assigned to constants.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I did, bad dog!
Added tests, optimized table loading as best as possible atm |
assert_equal "attachment; filename=\"hosts-#{Date.today}.csv\"", response.headers["Content-Disposition"] | ||
buf = response.stream.instance_variable_get(:@buf) | ||
assert buf.is_a? Enumerator | ||
assert_equal "Name,Subscription Status,Installable Updates - Security,Installable Updates - Bug Fixes,Installable Updates - Enhancements,Installable Updates - Package Count,OS,Environment,Content View,Registered,Last Checkin\n", buf.next |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Line is too long. [243/200]
assert_equal "attachment; filename=\"hosts-#{Date.today}.csv\"", response.headers["Content-Disposition"] | ||
buf = response.stream.instance_variable_get(:@buf) | ||
assert buf.is_a? Enumerator | ||
assert_equal "Name,Subscription Status,Installable Updates - Security,Installable Updates - Bug Fixes,Installable Updates - Enhancements,Installable Updates - Package Count,OS,Environment,Content View,Registered,Last Checkin\n", buf.next |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Line is too long. [243/200]
assert_equal "attachment; filename=\"hosts-#{Date.today}.csv\"", response.headers["Content-Disposition"] | ||
buf = response.stream.instance_variable_get(:@buf) | ||
assert buf.is_a? Enumerator | ||
assert_equal "Name,Subscription Status,Installable Updates - Security,Installable Updates - Bug Fixes,Installable Updates - Enhancements,Installable Updates - Package Count,OS,Environment,Content View,Registered,Last Checkin\n", buf.next |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Line is too long. [243/200]
buf = response.stream.instance_variable_get(:@buf) | ||
assert buf.is_a? Enumerator | ||
assert_equal "Name,Subscription Status,Installable Updates - Security,Installable Updates - Bug"+ | ||
" Fixes,Installable Updates - Enhancements,Installable Updates - Package Count,OS,Environment,"+ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Surrounding space missing for operator +.
Use \ instead of + or << to concatenate those strings.
assert_equal "attachment; filename=\"hosts-#{Date.today}.csv\"", response.headers["Content-Disposition"] | ||
buf = response.stream.instance_variable_get(:@buf) | ||
assert buf.is_a? Enumerator | ||
assert_equal "Name,Subscription Status,Installable Updates - Security,Installable Updates - Bug"+ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Surrounding space missing for operator +.
Use \ instead of + or << to concatenate those strings.
@@ -5,6 +5,9 @@ <h2 translate>Content Hosts</h2> | |||
</div> | |||
|
|||
<div data-block="list-actions"> | |||
<a href="/hosts/content_hosts.csv?{{csvQuery}}" class="btn btn-default"> | |||
<span translate>Export</span> | |||
</a> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
seeing a small issue with using this. It causes the URL to change which messes up things such as:
a) clicking export a 2nd time doesn't work
b) clicking 'search' does cause a 2nd download
adding target="_self"
seems to fix it. @waldenraines is that appropriate here?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Try ng-href
instead of href
. If that doesn't work I'm fine with this.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ng-href didn't fix it, added target.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ACK thanks @tbrisker
TODO: