foreman_rh_cloud 1.0.10 → 1.0.11

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (51) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +33 -0
  3. data/app/controllers/insights_cloud/hits_controller.rb +17 -0
  4. data/app/models/concerns/rh_cloud_host.rb +12 -0
  5. data/app/views/hosts/_insights_tab.html.erb +15 -0
  6. data/config/routes.rb +1 -0
  7. data/lib/foreman_inventory_upload/async/generate_report_job.rb +1 -1
  8. data/lib/foreman_inventory_upload/async/shell_process.rb +15 -9
  9. data/lib/foreman_inventory_upload/async/upload_report_job.rb +19 -1
  10. data/lib/foreman_inventory_upload/generators/metadata.rb +3 -0
  11. data/lib/foreman_inventory_upload/generators/queries.rb +2 -4
  12. data/lib/foreman_rh_cloud/engine.rb +10 -0
  13. data/lib/foreman_rh_cloud/version.rb +1 -1
  14. data/lib/tasks/insights.rake +15 -0
  15. data/lib/tasks/{generator.rake → rh_cloud_inventory.rake} +7 -1
  16. data/package.json +3 -1
  17. data/test/jobs/upload_report_job_test.rb +34 -0
  18. data/test/unit/metadata_generator_test.rb +2 -0
  19. data/test/unit/slice_generator_test.rb +17 -0
  20. data/webpack/ForemanInventoryUpload/Components/InventoryFilter/__tests__/__snapshots__/integration.test.js.snap +3 -0
  21. data/webpack/ForemanInventoryUpload/Components/PageHeader/components/SyncButton/components/Toast.js +1 -1
  22. data/webpack/ForemanInventoryUpload/Components/StatusChart/StatusChart.js +1 -1
  23. data/webpack/ForemanInventoryUpload/Components/StatusChart/__tests__/__snapshots__/StatusChart.test.js.snap +1 -1
  24. data/webpack/ForemanInventoryUpload/Components/TabContainer/tabContainer.scss +1 -1
  25. data/webpack/ForemanRhCloudPages.js +2 -0
  26. data/webpack/ForemanRhCloudReducers.js +2 -0
  27. data/webpack/ForemanRhCloudSelectors.js +5 -0
  28. data/webpack/ForemanRhCloudTestHelpers.js +6 -1
  29. data/webpack/InsightsHostDetailsTab/InsightsTab.js +64 -0
  30. data/webpack/InsightsHostDetailsTab/InsightsTab.scss +86 -0
  31. data/webpack/InsightsHostDetailsTab/InsightsTabActions.js +30 -0
  32. data/webpack/InsightsHostDetailsTab/InsightsTabConstants.js +3 -0
  33. data/webpack/InsightsHostDetailsTab/InsightsTabReducer.js +26 -0
  34. data/webpack/InsightsHostDetailsTab/InsightsTabSelectors.js +3 -0
  35. data/webpack/InsightsHostDetailsTab/__tests__/InsightsTab.fixtures.js +25 -0
  36. data/webpack/InsightsHostDetailsTab/__tests__/InsightsTab.test.js +13 -0
  37. data/webpack/InsightsHostDetailsTab/__tests__/InsightsTabActions.test.js +13 -0
  38. data/webpack/InsightsHostDetailsTab/__tests__/InsightsTabIntegration.test.js +17 -0
  39. data/webpack/InsightsHostDetailsTab/__tests__/InsightsTabReducer.test.js +35 -0
  40. data/webpack/InsightsHostDetailsTab/__tests__/InsightsTabSelectors.test.js +13 -0
  41. data/webpack/InsightsHostDetailsTab/__tests__/__snapshots__/InsightsTab.test.js.snap +30 -0
  42. data/webpack/InsightsHostDetailsTab/__tests__/__snapshots__/InsightsTabActions.test.js.snap +20 -0
  43. data/webpack/InsightsHostDetailsTab/__tests__/__snapshots__/InsightsTabReducer.test.js.snap +41 -0
  44. data/webpack/InsightsHostDetailsTab/__tests__/__snapshots__/InsightsTabSelectors.test.js.snap +20 -0
  45. data/webpack/InsightsHostDetailsTab/components/ListItem/ListItem.js +69 -0
  46. data/webpack/InsightsHostDetailsTab/components/ListItem/index.js +1 -0
  47. data/webpack/InsightsHostDetailsTab/index.js +20 -0
  48. data/webpack/__tests__/__snapshots__/ForemanRhCloudSelectors.test.js.snap +1 -0
  49. data/webpack/__tests__/__snapshots__/ForemanRhCloudTestHelpers.test.js.snap +3 -0
  50. data/webpack/stories/decorators/withCardsDecorator.js +1 -1
  51. metadata +38 -13
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: fb457584e95614e52c7026cb963409b2a2ea645b082315c0004b787db6ecf028
4
- data.tar.gz: 6352df86d12f35dbdc4d90538c1604aa00e1c4710f09c6deb0066efce8a48277
3
+ metadata.gz: f2b89191efb4cb97cec7c9e2a2d1cc41e255f02f7c04e95ecf7c1753e3b718ed
4
+ data.tar.gz: 38846a43180f47c4ebf888b8af0624a3edf460a10b0e3f02eca17bdd074f5142
5
5
  SHA512:
6
- metadata.gz: 1299b5836e5bf30151c690e5c222c67d34f351b0e5ffbd4e3ffeead0109457adce46279a1ddb550f3468aac4439c1050e366bf831dfb3c84b3e021e5cc2d9dd3
7
- data.tar.gz: edc7f560cd4ed663a07535bc247b0d5baf7e5755a50f002e9c752116cda93b729a15cc7b4452c12a95d9cee542d7201f900142f408abfa43a8e308d390305aa2
6
+ metadata.gz: 1d1fd157774d8b4d2007ea0139b05c6d39a749d432f6e1bcdb3d5efa5f39480743e1220434037131ccf65486edcd1fde24de39ed165653aa074062131d957394
7
+ data.tar.gz: 531cc12e64d7a4f8957029f7d7517dd80d30758c9ba070dd2603c5e64f324d399484824cc160dca8bef53810fa44aaeaf77e92e6a2d6ffdeb1f634b316a2af6e
data/README.md CHANGED
@@ -11,6 +11,39 @@ for how to install Foreman plugins
11
11
 
12
12
  *Usage here*
13
13
 
14
+ ### In Satellite
15
+
16
+ #### Inventory upload
17
+
18
+ In UI: Configure -> Inventory Upload -> Restart
19
+
20
+ From command-line:
21
+
22
+ export organization_id=1
23
+ export target=/var/lib/foreman/red_hat_inventory/generated_reports/
24
+ /usr/sbin/foreman-rake rh_cloud_inventory:report:generate
25
+
26
+ #### Fetch hosts remediation data
27
+
28
+ In UI: Configure -> Insights -> Sync now
29
+
30
+ From command-line:
31
+
32
+ /usr/sbin/foreman-rake rh_cloud_inventory:sync
33
+
34
+ #### Synchronize inventory status
35
+
36
+ In UI: Configure -> Inventory Upload -> Sync inventory status
37
+
38
+ From command-line:
39
+
40
+ # all organizations
41
+ /usr/sbin/foreman-rake rh_cloud_insights:sync
42
+
43
+ # specific organization with id 1
44
+ export organization_id=1
45
+ /usr/sbin/foreman-rake rh_cloud_insights:sync
46
+
14
47
  ## TODO
15
48
 
16
49
  *Todo list here*
@@ -0,0 +1,17 @@
1
+ module InsightsCloud
2
+ class HitsController < ::ApplicationController
3
+ def index
4
+ host = Host.where(id: host_id_param).first
5
+
6
+ render json: {
7
+ hits: host.insights.hits,
8
+ }, status: :ok
9
+ end
10
+
11
+ private
12
+
13
+ def host_id_param
14
+ params.require(:host_id)
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,12 @@
1
+ module RhCloudHost
2
+ extend ActiveSupport::Concern
3
+
4
+ included do
5
+ has_many(
6
+ :inventory_upload_facts,
7
+ -> { where(fact_name_id: ForemanInventoryUpload::Generators::Queries.fact_names.values) },
8
+ class_name: 'FactValue',
9
+ :foreign_key => :host_id
10
+ )
11
+ end
12
+ end
@@ -0,0 +1,15 @@
1
+ <% content_for(:javascripts) do %>
2
+ <%= webpacked_plugins_js_for :'foreman_rh_cloud' %>
3
+ <% end %>
4
+
5
+ <% content_for(:stylesheets) do %>
6
+ <%= webpacked_plugins_css_for :'foreman_rh_cloud' %>
7
+ <% end %>
8
+
9
+ <div id="host_details_insights_react_container"></div>
10
+ <%= mount_react_component(
11
+ 'InsightsHostDetailsTab',
12
+ '#host_details_insights_react_container',
13
+ { hostID: host.id }.to_json,
14
+ flatten_data: true
15
+ ) %>
@@ -15,6 +15,7 @@ Rails.application.routes.draw do
15
15
  namespace :insights_cloud do
16
16
  resources :tasks, only: [:create]
17
17
  resource :settings, only: [:show, :update]
18
+ get 'hits/:host_id', to: 'hits#index'
18
19
  end
19
20
 
20
21
  namespace :foreman_rh_cloud do
@@ -23,7 +23,7 @@ module ForemanInventoryUpload
23
23
  end
24
24
 
25
25
  def command
26
- "#{rake_prefix}rake foreman_inventory_upload:report:generate"
26
+ "#{rake_prefix}rake rh_cloud_inventory:report:generate"
27
27
  end
28
28
 
29
29
  def env
@@ -8,24 +8,30 @@ module ForemanInventoryUpload
8
8
  def perform(instance_label)
9
9
  klass_name = self.class.name
10
10
  logger.debug("Starting #{klass_name} with label #{instance_label}")
11
- progress_output = ProgressOutput.register(instance_label)
12
- Open3.popen2e(hash_to_s(env), command) do |_stdin, stdout_stderr, wait_thread|
13
- progress_output.status = "Running in pid #{wait_thread.pid}"
11
+ progress_output_for(instance_label) do |progress_output|
12
+ Open3.popen2e(hash_to_s(env), command) do |_stdin, stdout_stderr, wait_thread|
13
+ progress_output.status = "Running in pid #{wait_thread.pid}"
14
14
 
15
- stdout_stderr.each do |out_line|
16
- progress_output.write_line(out_line)
17
- end
15
+ stdout_stderr.each do |out_line|
16
+ progress_output.write_line(out_line)
17
+ end
18
18
 
19
- progress_output.status = wait_thread.value.to_s
19
+ progress_output.status = wait_thread.value.to_s
20
+ end
20
21
  end
21
22
  logger.debug("Finished job #{klass_name} with label #{instance_label}")
22
- ensure
23
- progress_output.close
24
23
  end
25
24
 
26
25
  def command
27
26
  end
28
27
 
28
+ def progress_output_for(instance_label)
29
+ progress_output = ProgressOutput.register(instance_label)
30
+ yield(progress_output)
31
+ ensure
32
+ progress_output.close
33
+ end
34
+
29
35
  def env
30
36
  {}
31
37
  end
@@ -8,15 +8,33 @@ module ForemanInventoryUpload
8
8
  end
9
9
 
10
10
  def perform(filename, organization_id)
11
+ label = UploadReportJob.output_label(organization_id)
11
12
  @filename = filename
12
13
  @organization = Organization.find(organization_id)
13
14
 
15
+ if Setting[:content_disconnected]
16
+ progress_output_for(label) do |progress_output|
17
+ progress_output.write_line('Upload was stopped since disconnected mode setting is enabled for content on this instance.')
18
+ progress_output.status = "Task aborted, exit 1"
19
+ end
20
+ return
21
+ end
22
+
23
+ unless @organization.owner_details&.fetch('upstreamConsumer')&.fetch('idCert')
24
+ logger.info("Skipping organization '#{@organization}', no candlepin certificate defined.")
25
+ progress_output_for(label) do |progress_output|
26
+ progress_output.write_line("Skipping organization #{@organization}, no candlepin certificate defined.")
27
+ progress_output.status = "Task aborted, exit 1"
28
+ end
29
+ return
30
+ end
31
+
14
32
  Tempfile.create([@organization.name, '.pem']) do |cer_file|
15
33
  cer_file.write(rh_credentials[:cert])
16
34
  cer_file.write(rh_credentials[:key])
17
35
  cer_file.flush
18
36
  @cer_path = cer_file.path
19
- super(UploadReportJob.output_label(organization_id))
37
+ super(label)
20
38
  end
21
39
  end
22
40
 
@@ -21,6 +21,9 @@ module ForemanInventoryUpload
21
21
  private
22
22
 
23
23
  def render_report(metadata)
24
+ metadata ||= {}
25
+ metadata['foreman_rh_cloud_version'] = ForemanRhCloud::VERSION
26
+
24
27
  @stream.object do
25
28
  @stream.simple_field('report_id', Foreman.uuid)
26
29
  @stream.simple_field('host_inventory_api_version', '1.0')
@@ -30,23 +30,21 @@ module ForemanInventoryUpload
30
30
  end
31
31
 
32
32
  def self.for_slice(base)
33
- fact_values = FactValue.where(fact_name_id: fact_names.values)
34
33
  base
35
34
  .joins(:subscription_facet)
36
- .eager_load(:fact_values)
37
35
  .preload(
38
36
  :interfaces,
39
37
  :installed_packages,
40
38
  :content_facet,
41
39
  :host_statuses,
40
+ :inventory_upload_facts,
42
41
  subscription_facet: [:pools, :installed_products, :hypervisor_host]
43
42
  )
44
- .merge(fact_values)
45
43
  end
46
44
 
47
45
  def self.for_report(portal_user)
48
46
  org_ids = organizations_for_user(portal_user).pluck(:id)
49
- for_slice(Host.unscoped.where(organization_id: org_ids)).in_batches(of: 1_000)
47
+ for_org(org_ids)
50
48
  end
51
49
 
52
50
  def self.for_org(organization_id)
@@ -66,9 +66,19 @@ module ForemanRhCloud
66
66
  register_global_js_file 'subscriptions_extension'
67
67
 
68
68
  register_custom_status(InventorySync::InventoryStatus)
69
+
70
+ extend_page 'hosts/show' do |context|
71
+ context.add_pagelet :main_tabs,
72
+ partial: 'hosts/insights_tab',
73
+ name: _('Insights'),
74
+ onlyif: proc { |host| host.insights }
75
+ end
69
76
  end
70
77
 
71
78
  ::Katello::UINotifications::Subscriptions::ManifestImportSuccess.include ForemanInventoryUpload::Notifications::ManifestImportSuccessNotificationOverride if defined?(Katello)
79
+
80
+ ::Host::Managed.include RhCloudHost
81
+ ::Host::Base.include RhCloudHost
72
82
  end
73
83
 
74
84
  initializer "foreman_rh_cloud.set_dynflow.config.on_init", :before => :finisher_hook do |_app|
@@ -1,3 +1,3 @@
1
1
  module ForemanRhCloud
2
- VERSION = '1.0.10'.freeze
2
+ VERSION = '1.0.11'.freeze
3
3
  end
@@ -0,0 +1,15 @@
1
+ namespace :rh_cloud_insights do
2
+ desc "Synchronize Insights inventory"
3
+ task sync: :environment do
4
+ if ! ENV['organization_id'].nil?
5
+ organizations = [ Organization.where(:id => ENV['organization_id']).first ]
6
+ else
7
+ organizations = Organization.all
8
+ end
9
+
10
+ organizations.each do |organization|
11
+ InventorySync::Async::InventoryFullSync.perform_now(organization)
12
+ puts "Synchronized inventory for organization '#{organization.name}'"
13
+ end
14
+ end
15
+ end
@@ -1,6 +1,6 @@
1
1
  require 'tempfile'
2
2
 
3
- namespace :foreman_inventory_upload do
3
+ namespace :rh_cloud_inventory do
4
4
  namespace :report do
5
5
  desc 'Generate inventory report to be sent to Red Hat cloud'
6
6
  task generate: :environment do
@@ -26,4 +26,10 @@ namespace :foreman_inventory_upload do
26
26
  end
27
27
  end
28
28
  end
29
+
30
+ desc "Synchronize Insights hosts hits"
31
+ task sync: :environment do
32
+ InsightsCloud::Async::InsightsFullSync.perform_now()
33
+ puts "Synchronized Insights hosts hits data"
34
+ end
29
35
  end
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "foreman_rh_cloud",
3
- "version": "0.0.1",
3
+ "version": "1.0.11",
4
4
  "description": "Inventory Upload =============",
5
5
  "main": "index.js",
6
6
  "scripts": {
@@ -47,6 +47,8 @@
47
47
  "eslint": "^4.10.0",
48
48
  "eslint-import-resolver-babel-module": "^4.0.0",
49
49
  "eslint-plugin-patternfly-react": "0.2.0",
50
+ "eslint-plugin-promise": "^4.2.1",
51
+ "eslint-plugin-spellcheck": "^0.0.17",
50
52
  "identity-obj-proxy": "^3.0.0",
51
53
  "jed": "^1.1.1",
52
54
  "jest-cli": "^23.6.0",
@@ -0,0 +1,34 @@
1
+ require 'test_plugin_helper'
2
+
3
+ class UploadReportJobTest < ActiveJob::TestCase
4
+ include FolderIsolation
5
+
6
+ test 'returns aborted state when disconnected' do
7
+ organization = FactoryBot.create(:organization)
8
+ Organization.any_instance.stubs(:owner_details).returns(
9
+ 'upstreamConsumer' => {
10
+ 'idCert' => 'TEST_CERT',
11
+ }
12
+ )
13
+ FactoryBot.create(:setting, :name => 'content_disconnected', :value => true)
14
+
15
+ ForemanInventoryUpload::Async::UploadReportJob.perform_now('', organization.id)
16
+
17
+ label = ForemanInventoryUpload::Async::UploadReportJob.output_label(organization.id)
18
+ progress_output = ForemanInventoryUpload::Async::ProgressOutput.get(label)
19
+ assert_match(/Upload was stopped/, progress_output.full_output)
20
+ assert_match(/exit 1/, progress_output.status)
21
+ end
22
+
23
+ test 'returns aborted state when no certificate defined on organization' do
24
+ organization = FactoryBot.create(:organization)
25
+ Organization.any_instance.expects(:owner_details).returns(nil)
26
+
27
+ ForemanInventoryUpload::Async::UploadReportJob.perform_now('', organization.id)
28
+
29
+ label = ForemanInventoryUpload::Async::UploadReportJob.output_label(organization.id)
30
+ progress_output = ForemanInventoryUpload::Async::ProgressOutput.get(label)
31
+ assert_match(/Skipping organization/, progress_output.full_output)
32
+ assert_match(/exit 1/, progress_output.status)
33
+ end
34
+ end
@@ -13,6 +13,8 @@ class MetadataGeneratorTest < ActiveSupport::TestCase
13
13
 
14
14
  assert_not_nil actual['report_id']
15
15
  assert_equal 'Satellite', actual['source']
16
+ assert_not_nil (actual_metadata = actual['source_metadata'])
17
+ assert_equal ForemanRhCloud::VERSION, actual_metadata['foreman_rh_cloud_version']
16
18
  assert_equal({}, actual['report_slices'])
17
19
  end
18
20
 
@@ -9,6 +9,7 @@ class ReportGeneratorTest < ActiveSupport::TestCase
9
9
 
10
10
  @host = FactoryBot.create(
11
11
  :host,
12
+ :redhat,
12
13
  :with_subscription,
13
14
  :with_content,
14
15
  content_view: cv.first,
@@ -264,6 +265,22 @@ class ReportGeneratorTest < ActiveSupport::TestCase
264
265
  assert_equal 1, generator.hosts_count
265
266
  end
266
267
 
268
+ test 'include also hosts with non-redhat OS' do
269
+ os = @host.operatingsystem
270
+ os.name = 'Centos'
271
+ os.save!
272
+
273
+ # make a_host last
274
+ batch = ForemanInventoryUpload::Generators::Queries.for_org(@host.organization_id).first
275
+ generator = create_generator(batch)
276
+
277
+ json_str = generator.render
278
+ actual = JSON.parse(json_str.join("\n"))
279
+
280
+ assert_equal 'slice_123', actual['report_slice_id']
281
+ assert_equal 1, generator.hosts_count
282
+ end
283
+
267
284
  test 'shows system_memory_bytes in bytes' do
268
285
  FactoryBot.create(:fact_value, fact_name: fact_names['memory::memtotal'], value: '1', host: @host)
269
286
 
@@ -19,6 +19,9 @@ Object {
19
19
  "insightsSyncEnabled": false,
20
20
  },
21
21
  },
22
+ "hostInsights": Object {
23
+ "hits": Array [],
24
+ },
22
25
  "inventoryUpload": Object {
23
26
  "accountsList": Object {
24
27
  "accounts": Object {},
@@ -8,7 +8,7 @@ const Toast = ({ syncHosts, disconnectHosts }) => {
8
8
  return (
9
9
  <span>
10
10
  <p>
11
- {__("Total org's hosts with subscriprion: ")}
11
+ {__('Hosts with subscription in organization: ')}
12
12
  <strong>{totalHosts}</strong>
13
13
  </p>
14
14
  <p>
@@ -27,7 +27,7 @@ const StatusChart = ({ completed }) => {
27
27
  <Grid.Col sm={4}>
28
28
  <div className="status-chart">
29
29
  <DonutChart
30
- id="donunt-chart-1"
30
+ id="donut-chart-1"
31
31
  size={{
32
32
  width: 210,
33
33
  height: 210,
@@ -43,7 +43,7 @@ exports[`StatusChart rendering render without Props 1`] = `
43
43
  "width": 11,
44
44
  }
45
45
  }
46
- id="donunt-chart-1"
46
+ id="donut-chart-1"
47
47
  legend={
48
48
  Object {
49
49
  "show": false,
@@ -1,4 +1,4 @@
1
- .tab-content {
1
+ .dashboard .tab-content {
2
2
  padding: 20px;
3
3
  min-height: 0;
4
4
 
@@ -1,7 +1,9 @@
1
1
  import ForemanInventoryUpload from './ForemanInventoryUpload';
2
2
  import InsightsCloudSync from './InsightsCloudSync';
3
+ import InsightsHostDetailsTab from './InsightsHostDetailsTab';
3
4
 
4
5
  export default [
5
6
  { name: 'ForemanInventoryUpload', type: ForemanInventoryUpload },
6
7
  { name: 'InsightsCloudSync', type: InsightsCloudSync },
8
+ { name: 'InsightsHostDetailsTab', type: InsightsHostDetailsTab },
7
9
  ];
@@ -1,10 +1,12 @@
1
1
  import { combineReducers } from 'redux';
2
2
  import inventoryUploadReducers from './ForemanInventoryUpload/ForemanInventoryUploadReducers';
3
3
  import insightsReducers from './InsightsCloudSync/InsightsCloudSyncReducers';
4
+ import { hostInsightsReducers } from './InsightsHostDetailsTab';
4
5
 
5
6
  export default {
6
7
  ForemanRhCloud: combineReducers({
7
8
  ...inventoryUploadReducers,
8
9
  ...insightsReducers,
10
+ ...hostInsightsReducers,
9
11
  }),
10
12
  };
@@ -1,5 +1,10 @@
1
1
  export const selectForemanRhCloud = state => state.ForemanRhCloud;
2
+
2
3
  export const selectForemanInventoryUpload = state =>
3
4
  selectForemanRhCloud(state).inventoryUpload;
5
+
4
6
  export const selectInsightsCloudSync = state =>
5
7
  selectForemanRhCloud(state).InsightsCloudSync;
8
+
9
+ export const selectHostInsights = state =>
10
+ selectForemanRhCloud(state).hostInsights;
@@ -1,10 +1,12 @@
1
1
  export const rhCloudStateWrapper = (
2
2
  inventoryState = {},
3
- insightsState = {}
3
+ insightsState = {},
4
+ hostInsightsState = {}
4
5
  ) => ({
5
6
  ForemanRhCloud: {
6
7
  inventoryUpload: { ...inventoryState },
7
8
  InsightsCloudSync: { ...insightsState },
9
+ hostInsights: { ...hostInsightsState },
8
10
  },
9
11
  });
10
12
 
@@ -13,3 +15,6 @@ export const inventoryStateWrapper = innerState =>
13
15
 
14
16
  export const insightsStateWrapper = innerState =>
15
17
  rhCloudStateWrapper({}, innerState);
18
+
19
+ export const hostInsightsStateWrapper = innerState =>
20
+ rhCloudStateWrapper({}, {}, innerState);
@@ -0,0 +1,64 @@
1
+ import React from 'react';
2
+ import PropTypes from 'prop-types';
3
+ import { orderBy } from 'lodash';
4
+ import { Grid, ListView, noop } from 'patternfly-react';
5
+ import ListItem from './components/ListItem';
6
+ import './InsightsTab.scss';
7
+
8
+ class InsightsHostDetailsTab extends React.Component {
9
+ componentDidMount() {
10
+ const { fetchHits, hostID } = this.props;
11
+ fetchHits(hostID);
12
+ }
13
+
14
+ render() {
15
+ const { hits } = this.props;
16
+
17
+ if (!hits.length) {
18
+ return <h2>No recommendations were found for this host!</h2>;
19
+ }
20
+ const hitsSorted = orderBy(hits, ['insights_hit.total_risk'], ['desc']);
21
+ const items = hitsSorted.map(
22
+ (
23
+ {
24
+ insights_hit: {
25
+ title,
26
+ total_risk: totalRisk,
27
+ results_url: resultsUrl,
28
+ solution_url: solutionUrl,
29
+ },
30
+ },
31
+ index
32
+ ) => (
33
+ <ListItem
34
+ key={index}
35
+ title={title}
36
+ totalRisk={totalRisk}
37
+ resultsUrl={resultsUrl}
38
+ solutionUrl={solutionUrl}
39
+ />
40
+ )
41
+ );
42
+ return (
43
+ <Grid.Row>
44
+ <Grid.Col xs={12}>
45
+ <h2>Recommendations</h2>
46
+ <ListView id="hits_list">{items}</ListView>
47
+ </Grid.Col>
48
+ </Grid.Row>
49
+ );
50
+ }
51
+ }
52
+
53
+ InsightsHostDetailsTab.propTypes = {
54
+ hostID: PropTypes.number.isRequired,
55
+ fetchHits: PropTypes.func,
56
+ hits: PropTypes.array,
57
+ };
58
+
59
+ InsightsHostDetailsTab.defaultProps = {
60
+ fetchHits: noop,
61
+ hits: [],
62
+ };
63
+
64
+ export default InsightsHostDetailsTab;
@@ -0,0 +1,86 @@
1
+ #host_details_insights_react_container {
2
+ #btn_toolbar {
3
+ float: right;
4
+ }
5
+
6
+ #btn_fullscreen {
7
+ margin-left: 5px;
8
+
9
+ .fa-arrows-alt {
10
+ margin-left: 5px;
11
+ }
12
+ }
13
+
14
+ h2 {
15
+ margin-top: 5px;
16
+ }
17
+
18
+ #hits_list {
19
+ max-height: 650px;
20
+ overflow-y: scroll;
21
+ overflow-x: hidden;
22
+ margin-top: 15px;
23
+
24
+ .list-view-pf-expand {
25
+ padding: 0;
26
+ }
27
+
28
+ .list-group-item-header {
29
+ .list-view-pf-expand .fa-angle-right {
30
+ margin-top: 6px;
31
+ }
32
+
33
+ .list-view-pf-main-info .list-view-pf-description {
34
+ width: 83%;
35
+
36
+ .list-group-item-heading {
37
+ width: 375px;
38
+ }
39
+
40
+ p {
41
+ margin: 0;
42
+ font-size: 14px;
43
+ }
44
+ }
45
+
46
+ .list-view-pf-additional-info {
47
+ .risk-label {
48
+ padding: 5px 8px;
49
+ border-radius: 12px;
50
+
51
+ &.Low {
52
+ background-color: #e7f1fa;
53
+ }
54
+
55
+ &.Moderate {
56
+ background-color: #fdf7e7;
57
+ }
58
+
59
+ &.Important {
60
+ background-color: #f9dddd;
61
+ }
62
+
63
+ &.Critical {
64
+ background-color: #ffecec;
65
+ }
66
+
67
+ p {
68
+ margin: 0;
69
+ }
70
+ }
71
+ }
72
+ }
73
+
74
+ &::-webkit-scrollbar {
75
+ width: 12px;
76
+ height: 12px;
77
+ }
78
+
79
+ &::-webkit-scrollbar-thumb {
80
+ background: #0e0e0e6e;
81
+ border-radius: 6px;
82
+ border: 3px solid transparent;
83
+ background-clip: content-box;
84
+ }
85
+ }
86
+ }
@@ -0,0 +1,30 @@
1
+ import API from 'foremanReact/API';
2
+ import { insightsCloudUrl } from '../InsightsCloudSync/InsightsCloudSyncHelpers';
3
+ import {
4
+ INSIGHTS_HITS_REQUEST,
5
+ INSIGHTS_HITS_SUCCESS,
6
+ INSIGHTS_HITS_FAILURE,
7
+ } from './InsightsTabConstants';
8
+
9
+ export const fetchHits = hostID => async dispatch => {
10
+ try {
11
+ dispatch({
12
+ type: INSIGHTS_HITS_REQUEST,
13
+ payload: {},
14
+ });
15
+ const {
16
+ data: { hits },
17
+ } = await API.get(insightsCloudUrl(`hits/${hostID}`));
18
+ dispatch({
19
+ type: INSIGHTS_HITS_SUCCESS,
20
+ payload: { hits },
21
+ });
22
+ } catch (error) {
23
+ dispatch({
24
+ type: INSIGHTS_HITS_FAILURE,
25
+ payload: {
26
+ error: error.message,
27
+ },
28
+ });
29
+ }
30
+ };
@@ -0,0 +1,3 @@
1
+ export const INSIGHTS_HITS_REQUEST = 'INSIGHTS_HITS_REQUEST';
2
+ export const INSIGHTS_HITS_SUCCESS = 'INSIGHTS_HITS_SUCCESS';
3
+ export const INSIGHTS_HITS_FAILURE = 'INSIGHTS_HITS_FAILURE';
@@ -0,0 +1,26 @@
1
+ import Immutable from 'seamless-immutable';
2
+ import {
3
+ INSIGHTS_HITS_SUCCESS,
4
+ INSIGHTS_HITS_FAILURE,
5
+ } from './InsightsTabConstants';
6
+
7
+ const initialState = Immutable({
8
+ hits: [],
9
+ });
10
+
11
+ export default (state = initialState, action) => {
12
+ const { payload: { hits, error } = {} } = action;
13
+
14
+ switch (action.type) {
15
+ case INSIGHTS_HITS_SUCCESS:
16
+ return state.merge({
17
+ hits,
18
+ });
19
+ case INSIGHTS_HITS_FAILURE:
20
+ return state.merge({
21
+ error,
22
+ });
23
+ default:
24
+ return state;
25
+ }
26
+ };
@@ -0,0 +1,3 @@
1
+ import { selectHostInsights } from '../ForemanRhCloudSelectors';
2
+
3
+ export const selectHits = state => selectHostInsights(state).hits;
@@ -0,0 +1,25 @@
1
+ export const hostID = 1234;
2
+
3
+ export const hits = [
4
+ {
5
+ insights_hit: {
6
+ hostname: 'my-host.example.com',
7
+ rhel_version: '7.8',
8
+ uuid: '4739b323-a343-4e89-b71b-81991b8dc656',
9
+ last_seen: '2020-08-19T04:43:09.068706Z',
10
+ title:
11
+ 'New Ansible Engine packages are inaccessible when dedicated Ansible repo is not enabled',
12
+ solution_url: 'https://access.redhat.com/node/3359651',
13
+ total_risk: 2,
14
+ likelihood: 2,
15
+ publish_date: '2018-04-16T10:03:16Z',
16
+ results_url:
17
+ 'https://cloud.redhat.com/insights/advisor/recommendations/ansible_deprecated_repo%7CANSIBLE_DEPRECATED_REPO/4739b323-a343-4e89-b71b-81991b8dc656/',
18
+ },
19
+ },
20
+ ];
21
+
22
+ export const props = {
23
+ hostID,
24
+ hits,
25
+ };
@@ -0,0 +1,13 @@
1
+ import { testComponentSnapshotsWithFixtures } from 'react-redux-test-utils';
2
+
3
+ import InsightsTab from '../InsightsTab';
4
+ import { props } from './InsightsTab.fixtures';
5
+
6
+ const fixtures = {
7
+ 'render with props': props,
8
+ };
9
+
10
+ describe('InsightsTab', () => {
11
+ describe('rendering', () =>
12
+ testComponentSnapshotsWithFixtures(InsightsTab, fixtures));
13
+ });
@@ -0,0 +1,13 @@
1
+ import { testActionSnapshotWithFixtures } from 'react-redux-test-utils';
2
+ import API from 'foremanReact/API';
3
+ import { fetchHits } from '../InsightsTabActions';
4
+ import { hostID, hits } from './InsightsTab.fixtures';
5
+
6
+ jest.mock('foremanReact/API');
7
+ API.get.mockImplementation(async () => hits);
8
+
9
+ const fixtures = {
10
+ 'should fetchHits': () => fetchHits(hostID),
11
+ };
12
+
13
+ describe('InsightsTab actions', () => testActionSnapshotWithFixtures(fixtures));
@@ -0,0 +1,17 @@
1
+ import React from 'react';
2
+ import { IntegrationTestHelper } from 'react-redux-test-utils';
3
+
4
+ import InsightsTab from '../index';
5
+ import reducers from '../../ForemanRhCloudReducers';
6
+ import { hostID } from './InsightsTab.fixtures';
7
+
8
+ describe('InsightsTab integration test', () => {
9
+ it('should flow', async () => {
10
+ const integrationTestHelper = new IntegrationTestHelper(reducers);
11
+ const component = integrationTestHelper.mount(
12
+ <InsightsTab hostID={hostID} />
13
+ );
14
+ component.update();
15
+ /** Create a Flow test */
16
+ });
17
+ });
@@ -0,0 +1,35 @@
1
+ import { testReducerSnapshotWithFixtures } from 'react-redux-test-utils';
2
+ import reducer from '../InsightsTabReducer';
3
+ import { hits } from './InsightsTab.fixtures';
4
+ import {
5
+ INSIGHTS_HITS_REQUEST,
6
+ INSIGHTS_HITS_SUCCESS,
7
+ INSIGHTS_HITS_FAILURE,
8
+ } from '../InsightsTabConstants';
9
+
10
+ const fixtures = {
11
+ 'should return the initial state': {},
12
+ 'should handle INSIGHTS_HITS_REQUEST': {
13
+ action: {
14
+ type: INSIGHTS_HITS_REQUEST,
15
+ payload: {},
16
+ },
17
+ },
18
+ 'should handle INSIGHTS_HITS_SUCCESS': {
19
+ action: {
20
+ type: INSIGHTS_HITS_SUCCESS,
21
+ payload: { hits },
22
+ },
23
+ },
24
+ 'should handle INSIGHTS_HITS_FAILURE': {
25
+ action: {
26
+ type: INSIGHTS_HITS_FAILURE,
27
+ payload: {
28
+ error: 'some-error',
29
+ },
30
+ },
31
+ },
32
+ };
33
+
34
+ describe('AccountList reducer', () =>
35
+ testReducerSnapshotWithFixtures(reducer, fixtures));
@@ -0,0 +1,13 @@
1
+ import { testSelectorsSnapshotWithFixtures } from 'react-redux-test-utils';
2
+ import { hostInsightsStateWrapper } from '../../ForemanRhCloudTestHelpers';
3
+ import { hits } from './InsightsTab.fixtures';
4
+ import { selectHits } from '../InsightsTabSelectors';
5
+
6
+ const state = hostInsightsStateWrapper({ hits });
7
+
8
+ const fixtures = {
9
+ 'should return hits': () => selectHits(state),
10
+ };
11
+
12
+ describe('InsightsTab selectors', () =>
13
+ testSelectorsSnapshotWithFixtures(fixtures));
@@ -0,0 +1,30 @@
1
+ // Jest Snapshot v1, https://goo.gl/fbAQLP
2
+
3
+ exports[`InsightsTab rendering render with props 1`] = `
4
+ <Row
5
+ bsClass="row"
6
+ componentClass="div"
7
+ >
8
+ <Col
9
+ bsClass="col"
10
+ componentClass="div"
11
+ xs={12}
12
+ >
13
+ <h2>
14
+ Recommendations
15
+ </h2>
16
+ <ListView
17
+ className=""
18
+ id="hits_list"
19
+ >
20
+ <ListItem
21
+ key="0"
22
+ resultsUrl="https://cloud.redhat.com/insights/advisor/recommendations/ansible_deprecated_repo%7CANSIBLE_DEPRECATED_REPO/4739b323-a343-4e89-b71b-81991b8dc656/"
23
+ solutionUrl="https://access.redhat.com/node/3359651"
24
+ title="New Ansible Engine packages are inaccessible when dedicated Ansible repo is not enabled"
25
+ totalRisk={2}
26
+ />
27
+ </ListView>
28
+ </Col>
29
+ </Row>
30
+ `;
@@ -0,0 +1,20 @@
1
+ // Jest Snapshot v1, https://goo.gl/fbAQLP
2
+
3
+ exports[`InsightsTab actions should fetchHits 1`] = `
4
+ Array [
5
+ Array [
6
+ Object {
7
+ "payload": Object {},
8
+ "type": "INSIGHTS_HITS_REQUEST",
9
+ },
10
+ ],
11
+ Array [
12
+ Object {
13
+ "payload": Object {
14
+ "error": "Cannot read property 'hits' of undefined",
15
+ },
16
+ "type": "INSIGHTS_HITS_FAILURE",
17
+ },
18
+ ],
19
+ ]
20
+ `;
@@ -0,0 +1,41 @@
1
+ // Jest Snapshot v1, https://goo.gl/fbAQLP
2
+
3
+ exports[`AccountList reducer should handle INSIGHTS_HITS_FAILURE 1`] = `
4
+ Object {
5
+ "error": "some-error",
6
+ "hits": Array [],
7
+ }
8
+ `;
9
+
10
+ exports[`AccountList reducer should handle INSIGHTS_HITS_REQUEST 1`] = `
11
+ Object {
12
+ "hits": Array [],
13
+ }
14
+ `;
15
+
16
+ exports[`AccountList reducer should handle INSIGHTS_HITS_SUCCESS 1`] = `
17
+ Object {
18
+ "hits": Array [
19
+ Object {
20
+ "insights_hit": Object {
21
+ "hostname": "my-host.example.com",
22
+ "last_seen": "2020-08-19T04:43:09.068706Z",
23
+ "likelihood": 2,
24
+ "publish_date": "2018-04-16T10:03:16Z",
25
+ "results_url": "https://cloud.redhat.com/insights/advisor/recommendations/ansible_deprecated_repo%7CANSIBLE_DEPRECATED_REPO/4739b323-a343-4e89-b71b-81991b8dc656/",
26
+ "rhel_version": "7.8",
27
+ "solution_url": "https://access.redhat.com/node/3359651",
28
+ "title": "New Ansible Engine packages are inaccessible when dedicated Ansible repo is not enabled",
29
+ "total_risk": 2,
30
+ "uuid": "4739b323-a343-4e89-b71b-81991b8dc656",
31
+ },
32
+ },
33
+ ],
34
+ }
35
+ `;
36
+
37
+ exports[`AccountList reducer should return the initial state 1`] = `
38
+ Object {
39
+ "hits": Array [],
40
+ }
41
+ `;
@@ -0,0 +1,20 @@
1
+ // Jest Snapshot v1, https://goo.gl/fbAQLP
2
+
3
+ exports[`InsightsTab selectors should return hits 1`] = `
4
+ Array [
5
+ Object {
6
+ "insights_hit": Object {
7
+ "hostname": "my-host.example.com",
8
+ "last_seen": "2020-08-19T04:43:09.068706Z",
9
+ "likelihood": 2,
10
+ "publish_date": "2018-04-16T10:03:16Z",
11
+ "results_url": "https://cloud.redhat.com/insights/advisor/recommendations/ansible_deprecated_repo%7CANSIBLE_DEPRECATED_REPO/4739b323-a343-4e89-b71b-81991b8dc656/",
12
+ "rhel_version": "7.8",
13
+ "solution_url": "https://access.redhat.com/node/3359651",
14
+ "title": "New Ansible Engine packages are inaccessible when dedicated Ansible repo is not enabled",
15
+ "total_risk": 2,
16
+ "uuid": "4739b323-a343-4e89-b71b-81991b8dc656",
17
+ },
18
+ },
19
+ ]
20
+ `;
@@ -0,0 +1,69 @@
1
+ import React, { Fragment } from 'react';
2
+ import { ListView, Icon } from 'patternfly-react';
3
+ import PropTypes from 'prop-types';
4
+
5
+ const labelMapper = {
6
+ 1: 'Low',
7
+ 2: 'Moderate',
8
+ 3: 'Important',
9
+ 4: 'Critical',
10
+ };
11
+
12
+ const ListItem = ({ title, totalRisk, resultsUrl, solutionUrl }) => {
13
+ const heading = (
14
+ <p className="ellipsis list-item-heading" title={title}>
15
+ {title}
16
+ </p>
17
+ );
18
+
19
+ const riskLabel = labelMapper[totalRisk];
20
+ const additionalInfo = [
21
+ <span key={`risk-info-${title}`} className={`risk-label ${riskLabel}`}>
22
+ <p>{riskLabel}</p>
23
+ </span>,
24
+ ];
25
+
26
+ const knowledgebaseLink = solutionUrl && (
27
+ <p>
28
+ <a href={solutionUrl} target="_blank" rel="noopener noreferrer">
29
+ Knowledgebase article <Icon name="external-link" />
30
+ </a>
31
+ </p>
32
+ );
33
+
34
+ const insightsCloudLink = resultsUrl && (
35
+ <p>
36
+ <a href={resultsUrl} target="_blank" rel="noopener noreferrer">
37
+ Read more about it in RH cloud insights <Icon name="external-link" />
38
+ </a>
39
+ </p>
40
+ );
41
+
42
+ return (
43
+ <ListView.Item
44
+ heading={heading}
45
+ additionalInfo={additionalInfo}
46
+ hideCloseIcon
47
+ >
48
+ <Fragment>
49
+ <p>{title}</p>
50
+ {knowledgebaseLink}
51
+ {insightsCloudLink}
52
+ </Fragment>
53
+ </ListView.Item>
54
+ );
55
+ };
56
+
57
+ ListItem.propTypes = {
58
+ title: PropTypes.string.isRequired,
59
+ totalRisk: PropTypes.number.isRequired,
60
+ resultsUrl: PropTypes.string,
61
+ solutionUrl: PropTypes.string,
62
+ };
63
+
64
+ ListItem.defaultProps = {
65
+ resultsUrl: '',
66
+ solutionUrl: '',
67
+ };
68
+
69
+ export default ListItem;
@@ -0,0 +1 @@
1
+ export { default } from './ListItem';
@@ -0,0 +1,20 @@
1
+ import { bindActionCreators } from 'redux';
2
+ import { connect } from 'react-redux';
3
+ import InsightsTab from './InsightsTab';
4
+ import * as actions from './InsightsTabActions';
5
+ import reducer from './InsightsTabReducer';
6
+ import { selectHits } from './InsightsTabSelectors';
7
+
8
+ // map state to props
9
+ const mapStateToProps = state => ({
10
+ hits: selectHits(state),
11
+ });
12
+
13
+ // map action dispatchers to props
14
+ const mapDispatchToProps = dispatch => bindActionCreators(actions, dispatch);
15
+
16
+ // export reducers
17
+ export const hostInsightsReducers = { hostInsights: reducer };
18
+
19
+ // export connected component
20
+ export default connect(mapStateToProps, mapDispatchToProps)(InsightsTab);
@@ -11,6 +11,7 @@ Object {
11
11
  "InsightsCloudSync": Object {
12
12
  "insightsChild": Object {},
13
13
  },
14
+ "hostInsights": Object {},
14
15
  "inventoryUpload": Object {
15
16
  "inventoryChild": Object {},
16
17
  },
@@ -6,6 +6,7 @@ Object {
6
6
  "InsightsCloudSync": Object {
7
7
  "insightsChild": Object {},
8
8
  },
9
+ "hostInsights": Object {},
9
10
  "inventoryUpload": Object {},
10
11
  },
11
12
  }
@@ -15,6 +16,7 @@ exports[`ForemanRhCloud helpers should return inventory wrapper 1`] = `
15
16
  Object {
16
17
  "ForemanRhCloud": Object {
17
18
  "InsightsCloudSync": Object {},
19
+ "hostInsights": Object {},
18
20
  "inventoryUpload": Object {
19
21
  "inventoryChild": Object {},
20
22
  },
@@ -28,6 +30,7 @@ Object {
28
30
  "InsightsCloudSync": Object {
29
31
  "insightsChild": Object {},
30
32
  },
33
+ "hostInsights": Object {},
31
34
  "inventoryUpload": Object {
32
35
  "inventoryChild": Object {},
33
36
  },
@@ -4,7 +4,7 @@ export const withCardsDecorator = storyFn => (
4
4
  <div
5
5
  style={{
6
6
  width: '100%',
7
- height: '100vh',
7
+ height: '100%',
8
8
  backgroundColor: '#F5F5F5',
9
9
  padding: '50px',
10
10
  }}
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: foreman_rh_cloud
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.10
4
+ version: 1.0.11
5
5
  platform: ruby
6
6
  authors:
7
7
  - Foreman Red Hat Cloud team
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2020-08-04 00:00:00.000000000 Z
11
+ date: 2020-09-16 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: katello
@@ -109,10 +109,12 @@ files:
109
109
  - app/controllers/foreman_inventory_upload/tasks_controller.rb
110
110
  - app/controllers/foreman_inventory_upload/uploads_controller.rb
111
111
  - app/controllers/foreman_rh_cloud/react_controller.rb
112
+ - app/controllers/insights_cloud/hits_controller.rb
112
113
  - app/controllers/insights_cloud/settings_controller.rb
113
114
  - app/controllers/insights_cloud/tasks_controller.rb
114
115
  - app/helpers/foreman_inventory_upload_helper.rb
115
116
  - app/helpers/foreman_inventory_upload_host_helper.rb
117
+ - app/models/concerns/rh_cloud_host.rb
116
118
  - app/models/insights_facet.rb
117
119
  - app/models/insights_hit.rb
118
120
  - app/models/inventory_sync/inventory_status.rb
@@ -120,6 +122,7 @@ files:
120
122
  - app/overrides/hosts_list.rb
121
123
  - app/views/foreman_rh_cloud/react/insights_cloud.html.erb
122
124
  - app/views/foreman_rh_cloud/react/inventory_upload.html.erb
125
+ - app/views/hosts/_insights_tab.html.erb
123
126
  - app/views/layouts/foreman_rh_cloud/application.html.erb
124
127
  - config/routes.rb
125
128
  - db/migrate/20191215104806_create_insights_hits.foreman_inventory_upload.rb
@@ -150,7 +153,8 @@ files:
150
153
  - lib/inventory_sync/async/host_result.rb
151
154
  - lib/inventory_sync/async/inventory_full_sync.rb
152
155
  - lib/tasks/foreman_rh_cloud_tasks.rake
153
- - lib/tasks/generator.rake
156
+ - lib/tasks/insights.rake
157
+ - lib/tasks/rh_cloud_inventory.rake
154
158
  - locale/Makefile
155
159
  - locale/en/foreman_rh_cloud.po
156
160
  - locale/foreman_rh_cloud.pot
@@ -164,6 +168,7 @@ files:
164
168
  - test/factories/inventory_upload_factories.rb
165
169
  - test/jobs/insights_full_sync_test.rb
166
170
  - test/jobs/inventory_full_sync_test.rb
171
+ - test/jobs/upload_report_job_test.rb
167
172
  - test/test_plugin_helper.rb
168
173
  - test/unit/archived_report_generator_test.rb
169
174
  - test/unit/fact_helpers_test.rb
@@ -458,6 +463,25 @@ files:
458
463
  - webpack/InsightsCloudSync/__tests__/InsightsCloudSyncHelpers.test.js
459
464
  - webpack/InsightsCloudSync/__tests__/__snapshots__/InsightsCloudSyncHelpers.test.js.snap
460
465
  - webpack/InsightsCloudSync/index.js
466
+ - webpack/InsightsHostDetailsTab/InsightsTab.js
467
+ - webpack/InsightsHostDetailsTab/InsightsTab.scss
468
+ - webpack/InsightsHostDetailsTab/InsightsTabActions.js
469
+ - webpack/InsightsHostDetailsTab/InsightsTabConstants.js
470
+ - webpack/InsightsHostDetailsTab/InsightsTabReducer.js
471
+ - webpack/InsightsHostDetailsTab/InsightsTabSelectors.js
472
+ - webpack/InsightsHostDetailsTab/__tests__/InsightsTab.fixtures.js
473
+ - webpack/InsightsHostDetailsTab/__tests__/InsightsTab.test.js
474
+ - webpack/InsightsHostDetailsTab/__tests__/InsightsTabActions.test.js
475
+ - webpack/InsightsHostDetailsTab/__tests__/InsightsTabIntegration.test.js
476
+ - webpack/InsightsHostDetailsTab/__tests__/InsightsTabReducer.test.js
477
+ - webpack/InsightsHostDetailsTab/__tests__/InsightsTabSelectors.test.js
478
+ - webpack/InsightsHostDetailsTab/__tests__/__snapshots__/InsightsTab.test.js.snap
479
+ - webpack/InsightsHostDetailsTab/__tests__/__snapshots__/InsightsTabActions.test.js.snap
480
+ - webpack/InsightsHostDetailsTab/__tests__/__snapshots__/InsightsTabReducer.test.js.snap
481
+ - webpack/InsightsHostDetailsTab/__tests__/__snapshots__/InsightsTabSelectors.test.js.snap
482
+ - webpack/InsightsHostDetailsTab/components/ListItem/ListItem.js
483
+ - webpack/InsightsHostDetailsTab/components/ListItem/index.js
484
+ - webpack/InsightsHostDetailsTab/index.js
461
485
  - webpack/__mocks__/foremanReact/API.js
462
486
  - webpack/__mocks__/foremanReact/common/I18n.js
463
487
  - webpack/__mocks__/foremanReact/common/helpers.js
@@ -498,23 +522,24 @@ required_rubygems_version: !ruby/object:Gem::Requirement
498
522
  - !ruby/object:Gem::Version
499
523
  version: '0'
500
524
  requirements: []
501
- rubygems_version: 3.0.6
525
+ rubygems_version: 3.0.8
502
526
  signing_key:
503
527
  specification_version: 4
504
528
  summary: Summary of ForemanRhCloud.
505
529
  test_files:
506
- - test/controllers/uploads_controller_test.rb
507
- - test/controllers/insights_sync/settings_controller_test.rb
508
- - test/controllers/accounts_controller_test.rb
509
- - test/controllers/reports_controller_test.rb
510
530
  - test/test_plugin_helper.rb
511
- - test/jobs/insights_full_sync_test.rb
512
- - test/jobs/inventory_full_sync_test.rb
513
531
  - test/factories/inventory_upload_factories.rb
514
532
  - test/factories/insights_factories.rb
515
- - test/unit/shell_process_job_test.rb
533
+ - test/controllers/reports_controller_test.rb
534
+ - test/controllers/uploads_controller_test.rb
535
+ - test/controllers/accounts_controller_test.rb
536
+ - test/controllers/insights_sync/settings_controller_test.rb
537
+ - test/unit/slice_generator_test.rb
516
538
  - test/unit/metadata_generator_test.rb
539
+ - test/unit/shell_process_job_test.rb
517
540
  - test/unit/insights_facet_test.rb
518
- - test/unit/fact_helpers_test.rb
519
541
  - test/unit/archived_report_generator_test.rb
520
- - test/unit/slice_generator_test.rb
542
+ - test/unit/fact_helpers_test.rb
543
+ - test/jobs/inventory_full_sync_test.rb
544
+ - test/jobs/insights_full_sync_test.rb
545
+ - test/jobs/upload_report_job_test.rb