Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
31 changes: 30 additions & 1 deletion app/controllers/katello/concerns/hosts_controller_extensions.rb
Original file line number Diff line number Diff line change
Expand Up @@ -15,13 +15,42 @@ def action_permission
super
end
end

def csv_pagelets
base_pagelets = super
# Only append Katello pagelets for /new/hosts.csv
return base_pagelets unless request.path.start_with?('/new/hosts')

# Get Katello pagelets from the :content profile
if @selected_columns
# User has customized columns - use their selection
katello_pagelets = Pagelets::Manager.pagelets_at('hosts/_list', 'hosts_table_column_header', profile: :content, filter: { selected: @selected_columns })
else
# No customization - use default Katello columns matching content_hosts method
all_katello_pagelets = Pagelets::Manager.pagelets_at('hosts/_list', 'hosts_table_column_header', profile: :content)
default_katello_columns = [:installable_updates, :content_view_environments, :registered_at, :last_checkin]
katello_pagelets = all_katello_pagelets.select { |p| default_katello_columns.include?(p.opts[:key]) }
end

# Exclude pagelets that are already in base (like :name which uses use_pagelet)
existing_keys = base_pagelets.map { |p| p.opts[:key] }
katello_pagelets = katello_pagelets.reject { |p| existing_keys.include?(p.opts[:key]) }

base_pagelets + katello_pagelets
end
end

included do
prepend Overrides

def included_associations(include = [])
[:host_traces] + super
base_associations = super
# Only add Katello associations for /new/hosts.csv
return base_associations unless request.path.start_with?('/new/hosts')

katello_associations = [:host_traces, :subscription_facet, :content_facet,
:applicable_rpms, :content_view_environments]
katello_associations + base_associations
end

def update_multiple_taxonomies(type)
Expand Down
24 changes: 18 additions & 6 deletions lib/katello/plugin.rb
Original file line number Diff line number Diff line change
Expand Up @@ -293,24 +293,36 @@
common_class = 'hidden-tablet hidden-xs ellipsis'
use_pagelet :hosts_table_column_header, :name
use_pagelet :hosts_table_column_content, :name
add_pagelet :hosts_table_column_header, key: :bootc_booted_image, label: _('Type'), sortable: true, class: common_class, width: '10%',
export_data: CsvExporter::ExportDefinition.new('content_facet_attributes.bootc_booted_image', label: 'Image Type')
add_pagelet :hosts_table_column_content, key: :bootc_booted_image, class: common_class, callback: ->(host) { host.content_facet&.bootc_booted_image }

add_pagelet :hosts_table_column_header, key: :rhel_lifecycle_status, label: _('RHEL Lifecycle status'), sortable: true, class: common_class, width: '10%', export_key: 'rhel_lifecycle_status'
add_pagelet :hosts_table_column_content, key: :rhel_lifecycle_status, class: common_class, callback: ->(host) { host_status_icon(host.rhel_lifecycle_global_status) }

add_pagelet :hosts_table_column_header, key: :installable_updates, label: _('Installable updates'), class: common_class, width: '15%',
export_data: [:security, :bugfix, :enhancement].map { |kind| CsvExporter::ExportDefinition.new("installable_updates.#{kind}", callback: ->(host) { (host.content_facet_attributes&.errata_counts || {})[kind] }) } +
[:rpm, :deb].map { |kind| CsvExporter::ExportDefinition.new("installable_packages.#{kind}", callback: ->(host) { host&.content_facet_attributes&.public_send("upgradable_#{kind}_count".to_sym) || 0 }) }
add_pagelet :hosts_table_column_content, key: :installable_updates, class: common_class, callback: ->(host) { errata_counts(host) }
use_pagelet :hosts_table_column_header, :os_title
use_pagelet :hosts_table_column_content, :os_title
add_pagelet :hosts_table_column_header, key: :last_checkin, label: _('Last checkin'), sortable: true, class: common_class, width: '10%', export_data: CsvExporter::ExportDefinition.new('subscription_facet_attributes.last_checkin', label: 'Last Checkin')
add_pagelet :hosts_table_column_content, key: :last_checkin, class: common_class, callback: ->(host) { host_checkin_time(host) }
add_pagelet :hosts_table_column_header, key: :content_view_environments, label: _('Content View Environments'), class: common_class, width: '15%',
export_data: CsvExporter::ExportDefinition.new('content_view_environment_labels', label: 'Content View Environments', callback: ->(host) { host.content_view_environment_labels })
add_pagelet :hosts_table_column_content, key: :content_view_environments, class: common_class, callback: ->(host) { host.content_view_environment_labels }
add_pagelet :hosts_table_column_header, key: :lifecycle_environment, label: _('Lifecycle environment'), sortable: true, class: common_class, width: '10%',
export_data: CsvExporter::ExportDefinition.new('single_lifecycle_environment', label: 'Lifecycle Environment')
export_data: CsvExporter::ExportDefinition.new('single_lifecycle_environment', label: 'Lifecycle Environment', callback: ->(host) { host.content_facet&.single_lifecycle_environment&.name })
add_pagelet :hosts_table_column_content, key: :lifecycle_environment, class: common_class, callback: ->(host) { host.content_facet&.single_lifecycle_environment&.name }
add_pagelet :hosts_table_column_header, key: :content_view, label: _('Content view'), sortable: true, class: common_class, width: '10%', export_data: CsvExporter::ExportDefinition.new('single_content_view', label: 'Content View')
add_pagelet :hosts_table_column_header, key: :content_view, label: _('Content view'), sortable: true, class: common_class, width: '10%',
export_data: CsvExporter::ExportDefinition.new('single_content_view', label: 'Content View', callback: ->(host) { host.content_facet&.single_content_view&.name })
add_pagelet :hosts_table_column_content, key: :content_view, class: common_class, callback: ->(host) { host.content_facet&.single_content_view&.name }
add_pagelet :hosts_table_column_header, key: :content_source, label: _('Content Source'), sortable: true, class: common_class, width: '12%',
export_data: CsvExporter::ExportDefinition.new('content_facet_attributes.content_source_name', label: 'Content Source')
add_pagelet :hosts_table_column_content, key: :content_source, class: common_class, callback: ->(host) { host.content_facet&.content_source&.name }
add_pagelet :hosts_table_column_header, key: :registered_at, label: _('Registered'), sortable: true, class: common_class, width: '10%', export_data: CsvExporter::ExportDefinition.new('subscription_facet_attributes.registered_at', label: 'Registered')
add_pagelet :hosts_table_column_content, key: :registered_at, class: common_class, callback: ->(host) { host_registered_time(host) }
add_pagelet :hosts_table_column_header, key: :last_checkin, label: _('Last checkin'), sortable: true, class: common_class, width: '10%', export_data: CsvExporter::ExportDefinition.new('subscription_facet_attributes.last_checkin', label: 'Last Checkin')
add_pagelet :hosts_table_column_content, key: :last_checkin, class: common_class, callback: ->(host) { host_checkin_time(host) }
add_pagelet :hosts_table_column_header, key: :host_collections, label: _('Host Collections'), class: common_class, width: '15%',
export_data: CsvExporter::ExportDefinition.new('host_collections', label: 'Host Collections', callback: ->(host) { host.host_collections.map(&:name).join(', ') })
add_pagelet :hosts_table_column_content, key: :host_collections, class: common_class, callback: ->(host) { host.host_collections.map(&:name).join(', ') }
end
end

Expand Down
93 changes: 93 additions & 0 deletions test/controllers/foreman/hosts_controller_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,99 @@
buf = response.stream.instance_variable_get(:@buf)
assert_equal 2, buf.count
end

def test_index_csv_includes_katello_columns_for_new_hosts_path
@request.path = '/new/hosts.csv'
# Select Katello content columns that user wants to see (in UI weight order)
User.current.table_preferences.create(name: 'hosts', columns: ['name', 'bootc_booted_image', 'rhel_lifecycle_status', 'installable_updates', 'last_checkin', 'content_view_environments', 'lifecycle_environment', 'content_view', 'content_source', 'registered_at', 'host_collections'])

Check failure on line 109 in test/controllers/foreman/hosts_controller_test.rb

View workflow job for this annotation

GitHub Actions / Rubocop / Rubocop

Layout/LineLength: Line is too long. [288/273]

get :index, params: { :format => 'csv' }
assert_response :success

buf = response.stream.instance_variable_get(:@buf)
header_line = buf.next

# Verify Katello columns are included (in UI weight order)
assert_includes header_line, "Image Type"
assert_includes header_line, "Installable Updates - Security"
assert_includes header_line, "Installable Updates - Bugfix"
assert_includes header_line, "Installable Updates - Enhancement"
assert_includes header_line, "Installable Packages - Rpm"
assert_includes header_line, "Last Checkin"
assert_includes header_line, "Content View Environments"
assert_includes header_line, "Lifecycle Environment"
assert_includes header_line, "Content View"
assert_includes header_line, "Content Source"
assert_includes header_line, "Registered"
assert_includes header_line, "Host Collections"
end

def test_index_csv_excludes_katello_columns_for_legacy_hosts_path
@request.path = '/hosts.csv'
User.current.table_preferences.create(name: 'hosts', columns: ['name'])

get :index, params: { :format => 'csv' }
assert_response :success

buf = response.stream.instance_variable_get(:@buf)
header_line = buf.next

# Verify Katello columns are NOT included
refute_includes header_line, "Installable Updates - Security"
refute_includes header_line, "Installable Updates - Bug Fixes"
refute_includes header_line, "Content View Environments"
end

def test_csv_pagelets_conditional_on_request_path
@request.path = '/new/hosts.csv'
# Select Katello content columns
User.current.table_preferences.create(name: 'hosts', columns: ['name', 'installable_updates', 'registered_at'])

get :index, params: { :format => 'csv' }
pagelets = @controller.send(:csv_pagelets)

# Verify Katello pagelets are appended
katello_keys = pagelets.map { |p| p.opts[:key] }
assert_includes(katello_keys, :installable_updates)
assert_includes(katello_keys, :registered_at)
end

def test_csv_pagelets_not_appended_for_legacy_path
@request.path = '/hosts.csv'
User.current.table_preferences.create(name: 'hosts', columns: ['name'])

get :index, params: { :format => 'csv' }
pagelets = @controller.send(:csv_pagelets)

# Verify Katello pagelets are NOT appended
katello_keys = pagelets.map { |p| p.opts[:key] }
refute_includes(katello_keys, :installable_updates)
refute_includes(katello_keys, :registered_at)
end

def test_csv_exports_default_katello_columns_when_no_preferences
@request.path = '/new/hosts.csv'
# Don't create any table preferences - user hasn't customized columns

get :index, params: { :format => 'csv' }
assert_response :success

buf = response.stream.instance_variable_get(:@buf)
header_line = buf.next

# Verify default Katello columns are included (matching content_hosts method)
assert_includes header_line, "Installable Updates - Security"
assert_includes header_line, "Installable Updates - Bugfix"
assert_includes header_line, "Installable Updates - Enhancement"
assert_includes header_line, "Installable Packages - Rpm"
assert_includes header_line, "Content View Environments"
assert_includes header_line, "Registered"
assert_includes header_line, "Last Checkin"

# Verify non-default Katello columns are NOT included
refute_includes(header_line, "Content Source")
refute_includes(header_line, "Host Collections")
end
end

context 'destroy with katello overrides' do
Expand Down
Loading