Skip to content

Conversation

@lfu
Copy link
Collaborator

@lfu lfu commented Dec 11, 2025

What are the changes introduced in this pull request?

Add missing Manage columns to pagelet for CSV export.

Requires theforeman/foreman#10793

Considerations taken when implementing this change?

What are the testing steps for this pull request?

Summary by Sourcery

Add CSV export support for RH Cloud host overview columns related to insights recommendations and CVE counts.

New Features:

  • Enable CSV export for the insights recommendations count column on the RH Cloud hosts overview.
  • Expose total CVEs as a new column on the RH Cloud hosts overview with CSV export support.

@sourcery-ai
Copy link

sourcery-ai bot commented Dec 11, 2025

Reviewer's guide (collapsed on small PRs)

Reviewer's Guide

Adds and wires up CSV export definitions for RH Cloud-specific host table columns, including recommendations count and a new Total CVEs column, so that these values are available in hosts overview CSV exports.

Sequence diagram for hosts CSV export with RH Cloud columns

sequenceDiagram
  actor User
  participant HostsUI
  participant ForemanServer
  participant RHCloudPlugin
  participant PageletRegistry
  participant CsvExporter
  participant HostModel

  User->>HostsUI: Click export CSV on hosts overview
  HostsUI->>ForemanServer: Request hosts CSV
  ForemanServer->>PageletRegistry: Resolve hosts_table_column_header pagelets
  PageletRegistry->>RHCloudPlugin: Load cloud profile pagelets
  RHCloudPlugin-->>PageletRegistry: Provide insights_recommendations_count and cves_count export definitions
  ForemanServer->>CsvExporter: Initialize export with column definitions

  loop For each host
    CsvExporter->>HostModel: Load host record
    CsvExporter->>HostModel: insights_hits
    HostModel-->>CsvExporter: Collection of insights_hits
    CsvExporter-->>CsvExporter: Count insights_hits for insights_recommendations_count

    CsvExporter->>HostModel: insights_attributes
    HostModel-->>CsvExporter: Hash with cves_count
    CsvExporter-->>CsvExporter: Extract cves_count via dig
  end

  CsvExporter-->>ForemanServer: Generated CSV file
  ForemanServer-->>HostsUI: Send CSV response
  HostsUI-->>User: Download CSV including Recommendations and Total CVEs columns
Loading

File-Level Changes

Change Details Files
Adjust CSV export definition for Insights recommendations count column to include a label while preserving existing behavior.
  • Wrap existing recommendations header pagelet with an updated CsvExporter::ExportDefinition including an explicit 'Recommendations' label
  • Retain the existing callback that counts insights_hits on the host for CSV export data
lib/foreman_rh_cloud/plugin.rb
Introduce a new Total CVEs column (header, cell content, and CSV export mapping) to the RH Cloud hosts list profile.
  • Add a hosts_table_column_header pagelet for cves_count with label 'Total CVEs', sizing, and CSS classes
  • Define a CsvExporter::ExportDefinition for cves_count with label 'Total CVEs' and a callback reading insights_attributes['cves_count']
  • Add a hosts_table_column_content pagelet for cves_count that renders the CVE count from insights_attributes or a fallback em dash when absent
lib/foreman_rh_cloud/plugin.rb

Tips and commands

Interacting with Sourcery

  • Trigger a new review: Comment @sourcery-ai review on the pull request.
  • Continue discussions: Reply directly to Sourcery's review comments.
  • Generate a GitHub issue from a review comment: Ask Sourcery to create an
    issue from a review comment by replying to it. You can also reply to a
    review comment with @sourcery-ai issue to create an issue from it.
  • Generate a pull request title: Write @sourcery-ai anywhere in the pull
    request title to generate a title at any time. You can also comment
    @sourcery-ai title on the pull request to (re-)generate the title at any time.
  • Generate a pull request summary: Write @sourcery-ai summary anywhere in
    the pull request body to generate a PR summary at any time exactly where you
    want it. You can also comment @sourcery-ai summary on the pull request to
    (re-)generate the summary at any time.
  • Generate reviewer's guide: Comment @sourcery-ai guide on the pull
    request to (re-)generate the reviewer's guide at any time.
  • Resolve all Sourcery comments: Comment @sourcery-ai resolve on the
    pull request to resolve all Sourcery comments. Useful if you've already
    addressed all the comments and don't want to see them anymore.
  • Dismiss all Sourcery reviews: Comment @sourcery-ai dismiss on the pull
    request to dismiss all existing Sourcery reviews. Especially useful if you
    want to start fresh with a new review - don't forget to comment
    @sourcery-ai review to trigger a new review!

Customizing Your Experience

Access your dashboard to:

  • Enable or disable review features such as the Sourcery-generated pull request
    summary, the reviewer's guide, and others.
  • Change the review language.
  • Add, remove or edit custom review instructions.
  • Adjust other review settings.

Getting Help

Copy link

@sourcery-ai sourcery-ai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey there - I've reviewed your changes - here's some feedback:

  • For the CSV export definitions, consider reusing the same localized label used for the column headers (label: _('Recommendations'), label: _('Total CVEs')) instead of hardcoded English strings to keep i18n consistent between UI and exports.
  • The content cell for cves_count falls back to the string '—'; double-check that this matches the convention used elsewhere in the hosts table (e.g., nil or empty output) to avoid inconsistent placeholder values in the UI.
Prompt for AI Agents
Please address the comments from this code review:

## Overall Comments
- For the CSV export definitions, consider reusing the same localized label used for the column headers (`label: _('Recommendations')`, `label: _('Total CVEs')`) instead of hardcoded English strings to keep i18n consistent between UI and exports.
- The content cell for `cves_count` falls back to the string `'—'`; double-check that this matches the convention used elsewhere in the hosts table (e.g., nil or empty output) to avoid inconsistent placeholder values in the UI.

## Individual Comments

### Comment 1
<location> `lib/foreman_rh_cloud/plugin.rb:145-148` </location>
<code_context>
+                        export_data: CsvExporter::ExportDefinition.new(:insights_recommendations_count, label: 'Recommendations', callback: ->(host) { host&.insights_hits&.count })
</code_context>

<issue_to_address>
**suggestion:** Use consistent i18n for export labels to match UI labels

For both `:insights_recommendations_count` and `:cves_count`, the table headers use translated labels (`_('RH Cloud')`, `_('Total CVEs')`), while the CSV `label:` arguments use raw strings (`'Recommendations'`, `'Total CVEs'`). If CSV headers are user-facing, please wrap these labels in `_()` as well so UI and export localization remain consistent.

Suggested implementation:

```ruby
                        export_data: CsvExporter::ExportDefinition.new(:insights_recommendations_count, label: _('Recommendations'), callback: ->(host) { host&.insights_hits&.count })

```

```ruby
                        export_data: CsvExporter::ExportDefinition.new(:cves_count, label: _('Total CVEs'), callback: ->(host) { host&.insights_attributes&.dig('cves_count') })

```
</issue_to_address>

Sourcery is free for open source - if you like our reviews please consider sharing them ✨
Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.

@lfu lfu force-pushed the 38427_export_hosts branch from c77983f to 5542621 Compare December 11, 2025 22:07
Copy link
Collaborator

@jeremylenz jeremylenz left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for opening the PR @lfu!

context.with_profile :cloud, _('RH Cloud'), default: true do
add_pagelet :hosts_table_column_header, key: :insights_recommendations_count, label: _('Recommendations'), sortable: true, width: '12%', class: 'hidden-xs ellipsis', priority: 100,
export_data: CsvExporter::ExportDefinition.new(:insights_recommendations_count, callback: ->(host) { host&.insights_hits&.count })
export_data: CsvExporter::ExportDefinition.new(:insights_recommendations_count, label: _('Recommendations'), callback: ->(host) { host&.insights_hits&.count })
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This won't work with IoP. Insights hits are not stored in our database. Rather, we make an API call to IoP services from the frontend:

`/insights_cloud/api/insights/v1/system/${uuid}`,
{ key: `HOST_RECS_COUNT_${uuid}` }

Not sure what that means for CSV export. Perhaps you could make the same call from the backend. Or if it's too much, we could disable this column for export, but I hope we don't have to.

export_data: CsvExporter::ExportDefinition.new(:insights_recommendations_count, label: _('Recommendations'), callback: ->(host) { host&.insights_hits&.count })
add_pagelet :hosts_table_column_content, key: :insights_recommendations_count, callback: ->(host) { hits_counts_cell(host) }, class: 'hidden-xs ellipsis text-center', priority: 100
add_pagelet :hosts_table_column_header, key: :cves_count, label: _('Total CVEs'), width: '12%', class: 'hidden-xs ellipsis',
export_data: CsvExporter::ExportDefinition.new(:cves_count, label: _('Total CVEs'), callback: ->(host) { host&.insights_attributes&.dig('cves_count') })
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Note that this column is only "relevant" for IoP; it is not available with hosted.

@lfu
Copy link
Collaborator Author

lfu commented Dec 12, 2025

CSV exports are synchronous batch operations in one request. Seems not a fit solution for IoP export which would make hundreds/thousands of sequential API calls during CSV generation depending on the number of hosts.

How about we keep the CSV export for hosted only until there is a better solution for IoP export?

@jeremylenz
Copy link
Collaborator

How about we keep the CSV export for hosted only until there is a better solution for IoP export?

That sounds good to me. In that case, we will not be able to export the CVE column.

@lfu
Copy link
Collaborator Author

lfu commented Dec 12, 2025

CVE data comes from external services rather than the local database.
Current CSV export works with data from local database in a synchronous call.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants