foreman_host_reports 0.0.3 → 0.0.4
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.
- checksums.yaml +4 -4
- data/app/controllers/api/v2/host_reports_controller.rb +5 -2
- data/app/controllers/concerns/foreman_host_reports/controller/parameters/host_report.rb +2 -1
- data/app/models/host_report.rb +1 -31
- data/app/models/report_keyword.rb +5 -0
- data/app/views/api/v2/host_reports/main.json.rabl +2 -1
- data/db/migrate/20211011141813_change_status_column.rb +10 -0
- data/db/seeds.d/60-reports_feature.rb +2 -0
- data/lib/foreman_host_reports/version.rb +1 -1
- data/package.json +10 -10
- data/test/controllers/api/v2/host_reports_controller_test.rb +43 -20
- data/test/factories/foreman_host_reports_factories.rb +4 -1
- data/webpack/__mocks__/foremanReact/common/HOC.js +30 -0
- data/webpack/__mocks__/foremanReact/common/I18n.js +7 -0
- data/webpack/__mocks__/foremanReact/common/helpers.js +7 -0
- data/webpack/__mocks__/foremanReact/common/urlHelpers.js +8 -0
- data/webpack/__mocks__/foremanReact/components/ForemanModal/ForemanModalActions.js +2 -0
- data/webpack/__mocks__/foremanReact/components/ForemanModal/ForemanModalHooks.js +10 -0
- data/webpack/__mocks__/foremanReact/components/ForemanModal/index.js +23 -0
- data/webpack/__mocks__/foremanReact/components/Pagination/PaginationWrapper.js +4 -0
- data/webpack/__mocks__/foremanReact/components/common/EmptyState.js +5 -0
- data/webpack/__mocks__/foremanReact/components/common/dates/RelativeDateTime.js +7 -0
- data/webpack/__mocks__/foremanReact/components/common/forms/ForemanForm.js +9 -0
- data/webpack/__mocks__/foremanReact/components/common/forms/FormField.js +3 -0
- data/webpack/__mocks__/foremanReact/components/common/table.js +26 -0
- data/webpack/__mocks__/foremanReact/constants.js +24 -0
- data/webpack/__mocks__/foremanReact/redux/API/APISelectors.js +6 -0
- data/webpack/__mocks__/foremanReact/redux/API/index.js +10 -0
- data/webpack/__mocks__/foremanReact/redux/actions/common/forms.js +1 -0
- data/webpack/__mocks__/foremanReact/redux/actions/toasts.js +8 -0
- data/webpack/__mocks__/foremanReact/routes/common/PageLayout/PageLayout.js +10 -0
- data/webpack/__mocks__/foremanReact/routes/common/PageLayout/components/ExportButton/ExportButton.js +10 -0
- data/webpack/src/Router/HostReports/IndexPage/Components/HostReportsTable/Components/Formatters/statusFormatter.js +9 -3
- data/webpack/src/Router/HostReports/IndexPage/Components/HostReportsTable/Components/StatusCell.js +24 -66
- data/webpack/src/Router/HostReports/IndexPage/__tests__/HostReportsIndexPage.test.js +40 -0
- data/webpack/src/Router/HostReports/IndexPage/__tests__/__snapshots__/HostReportsIndexPage.test.js.snap +67 -0
- metadata +27 -3
- data/webpack/test_setup.js +0 -17
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 488222c4e90b62231ba01365932c00ccb2619ea7f8225757bf84c423cd56b13a
|
4
|
+
data.tar.gz: 39f11ab9a01e780bff2105f09726f95b564d45169b6c9c2466e9846f0433aff8
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 9970feb6d0dd2593977eded7cade385a1a17743da6af330f3c5fb1c338dd62a63716b07b19bc5fd7fef1b22bd20147d08d9fc41639f570c6c2b43cd02100a36d
|
7
|
+
data.tar.gz: 76f80c8de18583d372beee125c791f8eef7fd41bbcb501c318951ab7708a311eb6905f3e94b5df841700c9c2f15a1157985cb23d8ea5661aac7f45d738286879
|
@@ -11,7 +11,7 @@ module Api
|
|
11
11
|
before_action :find_resource, only: %i[destroy]
|
12
12
|
before_action :resolve_ids, only: %i[create]
|
13
13
|
|
14
|
-
add_smart_proxy_filters :create, features:
|
14
|
+
add_smart_proxy_filters :create, features: ['Reports']
|
15
15
|
|
16
16
|
api :GET, '/host_reports/', N_('List host reports')
|
17
17
|
param_group :search_and_pagination, ::Api::V2::BaseController
|
@@ -34,7 +34,10 @@ module Api
|
|
34
34
|
param :host, String, required: true, desc: N_("Hostname of the report's host origin")
|
35
35
|
param :format, HostReport.formats.keys, required: false, desc: N_('Format of the report, e.g. Ansible')
|
36
36
|
param :reported_at, String, required: true, desc: N_('UTC time of the report')
|
37
|
-
param :
|
37
|
+
param :applied, Integer, required: false, desc: N_('Number of applied resources or tasks')
|
38
|
+
param :failed, Integer, required: false, desc: N_('Number of failed resources or tasks')
|
39
|
+
param :pending, Integer, required: false, desc: N_('Number of pending resources or tasks')
|
40
|
+
param :other, Integer, required: false, desc: N_('Number of other resources or tasks')
|
38
41
|
param :body, String, required: true, desc: N_('String with JSON formatted body of the report')
|
39
42
|
param :proxy, String, required: false, desc: N_('Hostname of the proxy processed the report')
|
40
43
|
param :keywords, Array, of: String, required: false, desc: N_('A list of keywords to associate with the report for better searching')
|
@@ -10,7 +10,8 @@ module ForemanHostReports
|
|
10
10
|
def host_report_params_filter
|
11
11
|
Foreman::ParameterFilter.new(::HostReport).tap do |filter|
|
12
12
|
# body is permitted in controller
|
13
|
-
filter.permit :format, :version, :host, :proxy, :reported_at,
|
13
|
+
filter.permit :format, :version, :host, :proxy, :reported_at,
|
14
|
+
:proxy_id, :host_id, :applied, :failed, :pending, :other
|
14
15
|
filter.permit :keywords => []
|
15
16
|
end
|
16
17
|
end
|
data/app/models/host_report.rb
CHANGED
@@ -10,7 +10,7 @@ class HostReport < ApplicationRecord
|
|
10
10
|
has_one :organization, through: :host
|
11
11
|
has_one :location, through: :host
|
12
12
|
|
13
|
-
validates :host_id, :reported_at,
|
13
|
+
validates :host_id, :reported_at, presence: true
|
14
14
|
|
15
15
|
enum format: {
|
16
16
|
# plain text report (no processing)
|
@@ -20,10 +20,6 @@ class HostReport < ApplicationRecord
|
|
20
20
|
ansible: 2,
|
21
21
|
}.freeze
|
22
22
|
|
23
|
-
STATUS = {
|
24
|
-
plain: %w[debug normal warning error],
|
25
|
-
}.freeze
|
26
|
-
|
27
23
|
scoped_search relation: :host, on: :name, complete_value: true, rename: :host, aliases: %i[host_name]
|
28
24
|
scoped_search relation: :proxy, on: :name, complete_value: true, rename: :proxy
|
29
25
|
scoped_search relation: :organization, on: :name, complete_value: true, rename: :organization
|
@@ -45,36 +41,10 @@ class HostReport < ApplicationRecord
|
|
45
41
|
|
46
42
|
default_scope -> { order('reported_at DESC') }
|
47
43
|
|
48
|
-
# TODO: temporary until we decide what will status bitfiled be exactly
|
49
|
-
# rubocop:disable Style/RescueModifier
|
50
|
-
def status
|
51
|
-
@status ||= case format
|
52
|
-
when 'puppet'
|
53
|
-
JSON.parse(body)['metrics']['resources']['values'] rescue []
|
54
|
-
when 'ansible'
|
55
|
-
JSON.parse(body)['status'] rescue {}
|
56
|
-
else
|
57
|
-
super
|
58
|
-
end
|
59
|
-
end
|
60
|
-
# rubocop:enable Style/RescueModifier
|
61
|
-
|
62
44
|
def report_keywords
|
63
45
|
ReportKeyword.where(id: report_keyword_ids)
|
64
46
|
end
|
65
47
|
|
66
|
-
def self.authorized_smart_proxy_features
|
67
|
-
@authorized_smart_proxy_features ||= %w[Puppet Ansible]
|
68
|
-
end
|
69
|
-
|
70
|
-
def self.register_smart_proxy_feature(feature)
|
71
|
-
@authorized_smart_proxy_features = (authorized_smart_proxy_features + [feature]).uniq
|
72
|
-
end
|
73
|
-
|
74
|
-
def self.unregister_smart_proxy_feature(feature)
|
75
|
-
@authorized_smart_proxy_features -= [feature]
|
76
|
-
end
|
77
|
-
|
78
48
|
def self.search_by_keyword(_key, operator, value)
|
79
49
|
conditions = sanitize_sql_for_conditions(["report_keywords.name #{operator} ?", value_to_sql(operator, value)])
|
80
50
|
keyword_ids = ReportKeyword.where(conditions).distinct.pluck(:id)
|
@@ -5,7 +5,8 @@ object @host_report
|
|
5
5
|
extends 'api/v2/host_reports/base'
|
6
6
|
extends 'api/v2/layouts/permissions'
|
7
7
|
|
8
|
-
attributes :format, :host_id, :proxy_id, :reported_at, :
|
8
|
+
attributes :format, :host_id, :proxy_id, :reported_at, :applied, :failed,
|
9
|
+
:pending, :other
|
9
10
|
|
10
11
|
node(:host_name) do |report|
|
11
12
|
report.host.name
|
@@ -0,0 +1,10 @@
|
|
1
|
+
class ChangeStatusColumn < ActiveRecord::Migration[6.0]
|
2
|
+
def change
|
3
|
+
remove_column :host_reports, :status, :bigint
|
4
|
+
|
5
|
+
add_column :host_reports, :applied, :integer, default: 0
|
6
|
+
add_column :host_reports, :failed, :integer, default: 0
|
7
|
+
add_column :host_reports, :pending, :integer, default: 0
|
8
|
+
add_column :host_reports, :other, :integer, default: 0
|
9
|
+
end
|
10
|
+
end
|
data/package.json
CHANGED
@@ -5,7 +5,7 @@
|
|
5
5
|
"main": "index.js",
|
6
6
|
"scripts": {
|
7
7
|
"lint": "tfm-lint --plugin -d /webpack",
|
8
|
-
"test": "tfm-test --
|
8
|
+
"test": "tfm-test --plugin",
|
9
9
|
"test:watch": "tfm-test --plugin --watchAll",
|
10
10
|
"test:current": "tfm-test --plugin --watch",
|
11
11
|
"publish-coverage": "tfm-publish-coverage",
|
@@ -21,25 +21,25 @@
|
|
21
21
|
"url": "http://projects.theforeman.org/projects/foreman_host_reports/issues"
|
22
22
|
},
|
23
23
|
"peerDependencies": {
|
24
|
-
"@theforeman/vendor": "
|
24
|
+
"@theforeman/vendor": "^8.15.0"
|
25
25
|
},
|
26
26
|
"dependencies": {
|
27
|
-
"react-intl": "^2.8.0",
|
28
27
|
"react-json-tree": "^0.11.0"
|
29
28
|
},
|
30
29
|
"devDependencies": {
|
31
30
|
"@babel/core": "^7.7.0",
|
32
31
|
"@sheerun/mutationobserver-shim": "^0.3.3",
|
33
|
-
"@theforeman/builder": "^8.
|
34
|
-
"@theforeman/eslint-plugin-foreman": "8.
|
35
|
-
"@theforeman/find-foreman": "^8.
|
36
|
-
"@theforeman/stories": "^8.
|
37
|
-
"@theforeman/test": "^8.
|
38
|
-
"@theforeman/vendor-dev": "^8.
|
32
|
+
"@theforeman/builder": "^8.15.0",
|
33
|
+
"@theforeman/eslint-plugin-foreman": "^8.15.0",
|
34
|
+
"@theforeman/find-foreman": "^8.15.0",
|
35
|
+
"@theforeman/stories": "^8.15.0",
|
36
|
+
"@theforeman/test": "^8.15.0",
|
37
|
+
"@theforeman/vendor-dev": "^8.15.0",
|
39
38
|
"babel-eslint": "^10.0.3",
|
40
39
|
"eslint": "^6.7.2",
|
41
40
|
"prettier": "^1.19.1",
|
42
41
|
"stylelint-config-standard": "^18.0.0",
|
43
|
-
"stylelint": "^9.3.0"
|
42
|
+
"stylelint": "^9.3.0",
|
43
|
+
"jed": "^1.1.1"
|
44
44
|
}
|
45
45
|
}
|
@@ -1,6 +1,15 @@
|
|
1
1
|
require 'test_plugin_helper'
|
2
2
|
|
3
3
|
class Api::V2::HostReportsControllerTest < ActionController::TestCase
|
4
|
+
setup do
|
5
|
+
@proxy = FactoryBot.create(:smart_proxy,
|
6
|
+
url: "http://reports.foreman.example.com",
|
7
|
+
features: [FactoryBot.create(:feature, name: 'Reports')])
|
8
|
+
Resolv.any_instance.stubs(:getnames).returns([URI.parse(@proxy.url).host])
|
9
|
+
SmartProxy.any_instance.stubs(:with_features).returns([@proxy])
|
10
|
+
ProxyAPI::V2::Features.any_instance.stubs(:features).returns({ "reports" => { "state" => "running" } })
|
11
|
+
end
|
12
|
+
|
4
13
|
context 'when user does not have permission to view hosts' do
|
5
14
|
let :host_report do
|
6
15
|
as_admin { FactoryBot.create(:host_report) }
|
@@ -38,7 +47,7 @@ class Api::V2::HostReportsControllerTest < ActionController::TestCase
|
|
38
47
|
post :create, params: {
|
39
48
|
host_report: {
|
40
49
|
host: host.name, body: report_body, reported_at: Time.current,
|
41
|
-
|
50
|
+
applied: 5, failed: 1, pending: 1, other: 0
|
42
51
|
},
|
43
52
|
}, session: set_session_user
|
44
53
|
assert_response :success
|
@@ -50,12 +59,30 @@ class Api::V2::HostReportsControllerTest < ActionController::TestCase
|
|
50
59
|
assert_response :unprocessable_entity
|
51
60
|
end
|
52
61
|
|
62
|
+
test 'store statuses' do
|
63
|
+
User.current = nil
|
64
|
+
post :create, params: {
|
65
|
+
host_report: {
|
66
|
+
host: host.name, body: report_body, reported_at: Time.current,
|
67
|
+
keywords: %w[HasError HasFailedResource],
|
68
|
+
applied: 5, failed: 1, pending: 1, other: 6
|
69
|
+
},
|
70
|
+
}, session: set_session_user
|
71
|
+
report = ActiveSupport::JSON.decode(@response.body)
|
72
|
+
assert_response :created
|
73
|
+
assert_equal 5, report['applied']
|
74
|
+
assert_equal 1, report['failed']
|
75
|
+
assert_equal 1, report['pending']
|
76
|
+
assert_equal 6, report['other']
|
77
|
+
end
|
78
|
+
|
53
79
|
test 'assign keywords' do
|
54
80
|
User.current = nil
|
55
81
|
post :create, params: {
|
56
82
|
host_report: {
|
57
83
|
host: host.name, body: report_body, reported_at: Time.current,
|
58
|
-
|
84
|
+
keywords: %w[HasError HasFailedResource],
|
85
|
+
applied: 5, failed: 1, pending: 1, other: 0
|
59
86
|
},
|
60
87
|
}, session: set_session_user
|
61
88
|
report = ActiveSupport::JSON.decode(@response.body)
|
@@ -69,14 +96,16 @@ class Api::V2::HostReportsControllerTest < ActionController::TestCase
|
|
69
96
|
post :create, params: {
|
70
97
|
host_report: {
|
71
98
|
host: host.name, body: report_body, reported_at: Time.current,
|
72
|
-
|
99
|
+
keywords: %w[HasError HasFailedResource],
|
100
|
+
applied: 5, failed: 1, pending: 1, other: 0
|
73
101
|
},
|
74
102
|
}, session: set_session_user
|
75
103
|
|
76
104
|
post :create, params: {
|
77
105
|
host_report: {
|
78
106
|
host: host.name, body: report_body, reported_at: Time.current,
|
79
|
-
|
107
|
+
keywords: %w[HasError HasFailedResource],
|
108
|
+
applied: 5, failed: 1, pending: 1, other: 0
|
80
109
|
},
|
81
110
|
}, session: set_session_user
|
82
111
|
end
|
@@ -90,7 +119,7 @@ class Api::V2::HostReportsControllerTest < ActionController::TestCase
|
|
90
119
|
post :create, params: {
|
91
120
|
host_report: {
|
92
121
|
host: host.name, body: report_body, reported_at: Time.current,
|
93
|
-
|
122
|
+
applied: 5, failed: 1, pending: 1, other: 0
|
94
123
|
},
|
95
124
|
}
|
96
125
|
assert_nil @controller.detected_proxy
|
@@ -101,18 +130,13 @@ class Api::V2::HostReportsControllerTest < ActionController::TestCase
|
|
101
130
|
Setting[:restrict_registered_smart_proxies] = true
|
102
131
|
Setting[:require_ssl_smart_proxies] = false
|
103
132
|
|
104
|
-
stub_smart_proxy_v2_features
|
105
|
-
proxy = smart_proxies(:puppetmaster)
|
106
|
-
as_admin { proxy.update_attribute(:url, 'http://configreports.foreman') }
|
107
|
-
proxy_host = URI.parse(proxy.url).host
|
108
|
-
Resolv.any_instance.stubs(:getnames).returns([proxy_host])
|
109
133
|
post :create, params: {
|
110
134
|
host_report: {
|
111
135
|
host: host.name, body: report_body, reported_at: Time.current,
|
112
|
-
|
136
|
+
applied: 5, failed: 1, pending: 1, other: 0
|
113
137
|
},
|
114
138
|
}
|
115
|
-
assert_equal proxy, @controller.detected_proxy
|
139
|
+
assert_equal @proxy, @controller.detected_proxy
|
116
140
|
assert_response :created
|
117
141
|
end
|
118
142
|
|
@@ -124,7 +148,7 @@ class Api::V2::HostReportsControllerTest < ActionController::TestCase
|
|
124
148
|
post :create, params: {
|
125
149
|
host_report: {
|
126
150
|
host: host.name, body: report_body, reported_at: Time.current,
|
127
|
-
|
151
|
+
applied: 5, failed: 1, pending: 1, other: 0
|
128
152
|
},
|
129
153
|
}
|
130
154
|
assert_response :forbidden
|
@@ -135,12 +159,12 @@ class Api::V2::HostReportsControllerTest < ActionController::TestCase
|
|
135
159
|
Setting[:require_ssl_smart_proxies] = true
|
136
160
|
|
137
161
|
@request.env['HTTPS'] = 'on'
|
138
|
-
@request.env['SSL_CLIENT_S_DN'] = 'CN=
|
162
|
+
@request.env['SSL_CLIENT_S_DN'] = 'CN=reports.foreman.example.com'
|
139
163
|
@request.env['SSL_CLIENT_VERIFY'] = 'SUCCESS'
|
140
164
|
post :create, params: {
|
141
165
|
host_report: {
|
142
166
|
host: host.name, body: report_body, reported_at: Time.current,
|
143
|
-
|
167
|
+
applied: 5, failed: 1, pending: 1, other: 0
|
144
168
|
},
|
145
169
|
}
|
146
170
|
assert_response :created
|
@@ -156,7 +180,7 @@ class Api::V2::HostReportsControllerTest < ActionController::TestCase
|
|
156
180
|
post :create, params: {
|
157
181
|
host_report: {
|
158
182
|
host: host.name, body: report_body, reported_at: Time.current,
|
159
|
-
|
183
|
+
applied: 5, failed: 1, pending: 1, other: 0
|
160
184
|
},
|
161
185
|
}
|
162
186
|
assert_response :forbidden
|
@@ -172,7 +196,7 @@ class Api::V2::HostReportsControllerTest < ActionController::TestCase
|
|
172
196
|
post :create, params: {
|
173
197
|
host_report: {
|
174
198
|
host: host.name, body: report_body, reported_at: Time.current,
|
175
|
-
|
199
|
+
applied: 5, failed: 1, pending: 1, other: 0
|
176
200
|
},
|
177
201
|
}
|
178
202
|
assert_response :forbidden
|
@@ -187,7 +211,7 @@ class Api::V2::HostReportsControllerTest < ActionController::TestCase
|
|
187
211
|
post :create, params: {
|
188
212
|
host_report: {
|
189
213
|
host: host.name, body: report_body, reported_at: Time.current,
|
190
|
-
|
214
|
+
applied: 5, failed: 1, pending: 1, other: 0
|
191
215
|
},
|
192
216
|
}
|
193
217
|
assert_response :forbidden
|
@@ -199,11 +223,10 @@ class Api::V2::HostReportsControllerTest < ActionController::TestCase
|
|
199
223
|
Setting[:require_ssl_smart_proxies] = true
|
200
224
|
SETTINGS[:require_ssl] = false
|
201
225
|
|
202
|
-
Resolv.any_instance.stubs(:getnames).returns(['else.where'])
|
203
226
|
post :create, params: {
|
204
227
|
host_report: {
|
205
228
|
host: host.name, body: report_body, reported_at: Time.current,
|
206
|
-
|
229
|
+
applied: 5, failed: 1, pending: 1, other: 0
|
207
230
|
},
|
208
231
|
}
|
209
232
|
assert_response :created
|
@@ -0,0 +1,30 @@
|
|
1
|
+
import React, { useEffect, useRef } from 'react';
|
2
|
+
|
3
|
+
export const withRenderHandler = ({ Component }) => componentProps => (
|
4
|
+
<Component {...componentProps} />
|
5
|
+
);
|
6
|
+
|
7
|
+
export const callOnMount = callback => WrappedComponent => componentProps => {
|
8
|
+
callback(componentProps);
|
9
|
+
|
10
|
+
return <WrappedComponent {...componentProps} />;
|
11
|
+
};
|
12
|
+
|
13
|
+
export const callOnPopState = callback => WrappedComponent => componentProps => {
|
14
|
+
const didMount = useRef(false);
|
15
|
+
const {
|
16
|
+
history: {
|
17
|
+
action,
|
18
|
+
location: { search },
|
19
|
+
},
|
20
|
+
} = componentProps;
|
21
|
+
useEffect(() => {
|
22
|
+
if (action === 'POP' && didMount.current) {
|
23
|
+
callback(componentProps);
|
24
|
+
} else {
|
25
|
+
didMount.current = true;
|
26
|
+
}
|
27
|
+
}, [search, action, componentProps]);
|
28
|
+
|
29
|
+
return <WrappedComponent {...componentProps} />;
|
30
|
+
};
|
@@ -0,0 +1,23 @@
|
|
1
|
+
import React from 'react';
|
2
|
+
import PropTypes from 'prop-types';
|
3
|
+
|
4
|
+
const ForemanModal = ({ children }) => <div className="modal">{children}</div>;
|
5
|
+
ForemanModal.Header = ({ children }) => (
|
6
|
+
<div className="modal-header">{children}</div>
|
7
|
+
);
|
8
|
+
ForemanModal.Footer = ({ children }) => (
|
9
|
+
<div className="modal-footer">{children}</div>
|
10
|
+
);
|
11
|
+
|
12
|
+
ForemanModal.propTypes = {
|
13
|
+
children: PropTypes.node,
|
14
|
+
};
|
15
|
+
|
16
|
+
ForemanModal.defaultProps = {
|
17
|
+
children: [],
|
18
|
+
};
|
19
|
+
|
20
|
+
ForemanModal.Header.propTypes = ForemanModal.propTypes;
|
21
|
+
ForemanModal.Footer.propTypes = ForemanModal.propTypes;
|
22
|
+
|
23
|
+
export default ForemanModal;
|
@@ -0,0 +1,26 @@
|
|
1
|
+
import React from 'react';
|
2
|
+
|
3
|
+
export const Table = () => <div className="table" />;
|
4
|
+
export const createTableReducer = jest.fn(controller => controller);
|
5
|
+
export const cellFormatter = cell => cell;
|
6
|
+
export const deleteActionCellFormatter = cell => cell;
|
7
|
+
export const sortableColumn = jest.fn();
|
8
|
+
export const column = (
|
9
|
+
property,
|
10
|
+
label,
|
11
|
+
headFormat,
|
12
|
+
cellFormat,
|
13
|
+
headProps = {},
|
14
|
+
cellProps = {}
|
15
|
+
) => ({
|
16
|
+
property,
|
17
|
+
header: {
|
18
|
+
label,
|
19
|
+
props: headProps,
|
20
|
+
formatters: headFormat,
|
21
|
+
},
|
22
|
+
cell: {
|
23
|
+
props: cellProps,
|
24
|
+
formatters: cellFormat,
|
25
|
+
},
|
26
|
+
});
|
@@ -0,0 +1,24 @@
|
|
1
|
+
export const STATUS = {
|
2
|
+
PENDING: 'PENDING',
|
3
|
+
RESOLVED: 'RESOLVED',
|
4
|
+
ERROR: 'ERROR',
|
5
|
+
};
|
6
|
+
|
7
|
+
export const getControllerSearchProps = (
|
8
|
+
controller,
|
9
|
+
id = 'searchBar',
|
10
|
+
canCreateBookmarks = true
|
11
|
+
) => ({
|
12
|
+
controller,
|
13
|
+
autocomplete: {
|
14
|
+
id,
|
15
|
+
searchQuery: '',
|
16
|
+
url: `${controller}/auto_complete_search`,
|
17
|
+
useKeyShortcuts: true,
|
18
|
+
},
|
19
|
+
bookmarks: {
|
20
|
+
url: '/api/bookmarks',
|
21
|
+
canCreateBookmarks,
|
22
|
+
documentationUrl: `4.1.5Searching`,
|
23
|
+
},
|
24
|
+
});
|
@@ -0,0 +1,6 @@
|
|
1
|
+
export const selectAPIResponse = (state, key) =>
|
2
|
+
selectAPIByKey(state, key).response;
|
3
|
+
|
4
|
+
export const selectAPIStatus = (state, key) => 'PENDING';
|
5
|
+
export const selectAPIByKey = (state, key) => state.API[key];
|
6
|
+
export const selectAPIError = (state, key) => ({ error: `${key} ERRROR` });
|
@@ -0,0 +1 @@
|
|
1
|
+
export const submitForm = jest.fn(() => '');
|
@@ -2,8 +2,14 @@ import React from 'react';
|
|
2
2
|
|
3
3
|
import StatusCell from '../StatusCell';
|
4
4
|
|
5
|
-
const statusFormatter = () => (
|
6
|
-
|
7
|
-
|
5
|
+
const statusFormatter = () => (_, { rowData }) => {
|
6
|
+
const statuses = {
|
7
|
+
applied: rowData.applied,
|
8
|
+
failed: rowData.failed,
|
9
|
+
pending: rowData.pending,
|
10
|
+
other: rowData.other,
|
11
|
+
};
|
12
|
+
return <StatusCell statuses={statuses} />;
|
13
|
+
};
|
8
14
|
|
9
15
|
export default statusFormatter;
|
data/webpack/src/Router/HostReports/IndexPage/Components/HostReportsTable/Components/StatusCell.js
CHANGED
@@ -4,74 +4,32 @@ import { capitalize } from 'lodash';
|
|
4
4
|
|
5
5
|
import './StatusCell.scss';
|
6
6
|
|
7
|
-
const StatusCell = ({
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
</li>
|
31
|
-
);
|
32
|
-
})}
|
33
|
-
</ul>
|
34
|
-
</td>
|
35
|
-
);
|
36
|
-
case 'ansible':
|
37
|
-
return (
|
38
|
-
<td>
|
39
|
-
<ul className="status-list">
|
40
|
-
{Object.keys(value).map(status => {
|
41
|
-
let style = '';
|
42
|
-
switch (status) {
|
43
|
-
case 'failed':
|
44
|
-
style = 'label-danger';
|
45
|
-
break;
|
46
|
-
case 'skipped':
|
47
|
-
style = 'label-warning';
|
48
|
-
break;
|
49
|
-
default:
|
50
|
-
style = 'label-info';
|
51
|
-
}
|
52
|
-
if (!value[status]) style = 'label-default';
|
53
|
-
return (
|
54
|
-
<li key={status}>
|
55
|
-
{`${capitalize(status)}: `}
|
56
|
-
<span className={`label ${style}`}>{value[status]}</span>
|
57
|
-
</li>
|
58
|
-
);
|
59
|
-
})}
|
60
|
-
</ul>
|
61
|
-
</td>
|
62
|
-
);
|
63
|
-
default:
|
64
|
-
return <td>N/A</td>;
|
65
|
-
}
|
66
|
-
};
|
7
|
+
const StatusCell = ({ statuses }) => (
|
8
|
+
<td>
|
9
|
+
<ul className="status-list">
|
10
|
+
{Object.keys(statuses).map(status => {
|
11
|
+
let style = '';
|
12
|
+
switch (status) {
|
13
|
+
case 'failed':
|
14
|
+
style = 'label-danger';
|
15
|
+
break;
|
16
|
+
default:
|
17
|
+
style = 'label-info';
|
18
|
+
}
|
19
|
+
if (!statuses[status]) style = 'label-default';
|
20
|
+
return (
|
21
|
+
<li key={status}>
|
22
|
+
{`${capitalize(status)}: `}
|
23
|
+
<span className={`label ${style}`}>{statuses[status]}</span>
|
24
|
+
</li>
|
25
|
+
);
|
26
|
+
})}
|
27
|
+
</ul>
|
28
|
+
</td>
|
29
|
+
);
|
67
30
|
|
68
31
|
StatusCell.propTypes = {
|
69
|
-
|
70
|
-
value: PropTypes.any.isRequired,
|
71
|
-
};
|
72
|
-
|
73
|
-
StatusCell.defaultProps = {
|
74
|
-
format: 'plain',
|
32
|
+
statuses: PropTypes.object.isRequired,
|
75
33
|
};
|
76
34
|
|
77
35
|
export default StatusCell;
|
@@ -0,0 +1,40 @@
|
|
1
|
+
import { testComponentSnapshotsWithFixtures } from '@theforeman/test';
|
2
|
+
import HostReportsIndexPage from '../IndexPage';
|
3
|
+
|
4
|
+
const fixtures = {
|
5
|
+
'render with minimal props': {
|
6
|
+
search: '',
|
7
|
+
history: { location: { search: '' } },
|
8
|
+
hostId: '1',
|
9
|
+
fetchAndPush: jest.fn(),
|
10
|
+
reloadWithSearch: jest.fn(),
|
11
|
+
isLoading: false,
|
12
|
+
hasError: false,
|
13
|
+
hasData: true,
|
14
|
+
itemCount: 1,
|
15
|
+
canCreate: true,
|
16
|
+
sort: {},
|
17
|
+
page: 1,
|
18
|
+
perPage: 20,
|
19
|
+
reports: [
|
20
|
+
{
|
21
|
+
id: '1',
|
22
|
+
hostId: '1',
|
23
|
+
hostName: 'foreman.example.com',
|
24
|
+
proxyId: '1',
|
25
|
+
proxyName: 'foreman.example.com',
|
26
|
+
format: 'plain',
|
27
|
+
reportedAt: '2021-01-19T12:34:02.841645028Z',
|
28
|
+
applied: 0,
|
29
|
+
failed: 0,
|
30
|
+
pending: 0,
|
31
|
+
other: 0,
|
32
|
+
},
|
33
|
+
],
|
34
|
+
},
|
35
|
+
};
|
36
|
+
|
37
|
+
describe('HostReportsIndexPage', () => {
|
38
|
+
describe('redering', () =>
|
39
|
+
testComponentSnapshotsWithFixtures(HostReportsIndexPage, fixtures));
|
40
|
+
});
|
@@ -0,0 +1,67 @@
|
|
1
|
+
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
2
|
+
|
3
|
+
exports[`HostReportsIndexPage redering render with minimal props 1`] = `
|
4
|
+
<PageLayout
|
5
|
+
header="Host Reports"
|
6
|
+
isLoading={false}
|
7
|
+
onBookmarkClick={[MockFunction]}
|
8
|
+
onSearch={[MockFunction]}
|
9
|
+
searchProps={
|
10
|
+
Object {
|
11
|
+
"autocomplete": Object {
|
12
|
+
"id": "searchBar",
|
13
|
+
"searchQuery": "",
|
14
|
+
"url": "host_reports/auto_complete_search",
|
15
|
+
"useKeyShortcuts": true,
|
16
|
+
},
|
17
|
+
"bookmarks": Object {
|
18
|
+
"canCreateBookmarks": true,
|
19
|
+
"documentationUrl": "4.1.5Searching",
|
20
|
+
"url": "/api/bookmarks",
|
21
|
+
},
|
22
|
+
"controller": "host_reports",
|
23
|
+
}
|
24
|
+
}
|
25
|
+
searchQuery=""
|
26
|
+
searchable={true}
|
27
|
+
toolbarButtons={
|
28
|
+
<ExportButton
|
29
|
+
title="Export"
|
30
|
+
url="/api/v2/host_reports/export"
|
31
|
+
/>
|
32
|
+
}
|
33
|
+
>
|
34
|
+
<WrappedHostReportsTable
|
35
|
+
fetchAndPush={[MockFunction]}
|
36
|
+
hostId="1"
|
37
|
+
itemCount={1}
|
38
|
+
pagination={
|
39
|
+
Object {
|
40
|
+
"page": 1,
|
41
|
+
"perPage": 20,
|
42
|
+
}
|
43
|
+
}
|
44
|
+
reloadWithSearch={[MockFunction]}
|
45
|
+
results={
|
46
|
+
Array [
|
47
|
+
Object {
|
48
|
+
"applied": 0,
|
49
|
+
"failed": 0,
|
50
|
+
"format": "plain",
|
51
|
+
"hostId": "1",
|
52
|
+
"hostName": "foreman.example.com",
|
53
|
+
"id": "1",
|
54
|
+
"other": 0,
|
55
|
+
"pending": 0,
|
56
|
+
"proxyId": "1",
|
57
|
+
"proxyName": "foreman.example.com",
|
58
|
+
"reportedAt": "2021-01-19T12:34:02.841645028Z",
|
59
|
+
},
|
60
|
+
]
|
61
|
+
}
|
62
|
+
setToDelete={[Function]}
|
63
|
+
sort={Object {}}
|
64
|
+
toDelete={Object {}}
|
65
|
+
/>
|
66
|
+
</PageLayout>
|
67
|
+
`;
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: foreman_host_reports
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.4
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Lukas Zapletal
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2021-10-
|
11
|
+
date: 2021-10-22 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rdoc
|
@@ -48,6 +48,8 @@ files:
|
|
48
48
|
- config/routes.rb
|
49
49
|
- db/migrate/20210112183526_add_host_reports.rb
|
50
50
|
- db/migrate/20210616133601_create_report_keywords.rb
|
51
|
+
- db/migrate/20211011141813_change_status_column.rb
|
52
|
+
- db/seeds.d/60-reports_feature.rb
|
51
53
|
- lib/foreman_host_reports.rb
|
52
54
|
- lib/foreman_host_reports/engine.rb
|
53
55
|
- lib/foreman_host_reports/version.rb
|
@@ -62,6 +64,26 @@ files:
|
|
62
64
|
- test/snapshots/foreman-web.json
|
63
65
|
- test/test_plugin_helper.rb
|
64
66
|
- test/unit/foreman_host_reports_test.rb
|
67
|
+
- webpack/__mocks__/foremanReact/common/HOC.js
|
68
|
+
- webpack/__mocks__/foremanReact/common/I18n.js
|
69
|
+
- webpack/__mocks__/foremanReact/common/helpers.js
|
70
|
+
- webpack/__mocks__/foremanReact/common/urlHelpers.js
|
71
|
+
- webpack/__mocks__/foremanReact/components/ForemanModal/ForemanModalActions.js
|
72
|
+
- webpack/__mocks__/foremanReact/components/ForemanModal/ForemanModalHooks.js
|
73
|
+
- webpack/__mocks__/foremanReact/components/ForemanModal/index.js
|
74
|
+
- webpack/__mocks__/foremanReact/components/Pagination/PaginationWrapper.js
|
75
|
+
- webpack/__mocks__/foremanReact/components/common/EmptyState.js
|
76
|
+
- webpack/__mocks__/foremanReact/components/common/dates/RelativeDateTime.js
|
77
|
+
- webpack/__mocks__/foremanReact/components/common/forms/ForemanForm.js
|
78
|
+
- webpack/__mocks__/foremanReact/components/common/forms/FormField.js
|
79
|
+
- webpack/__mocks__/foremanReact/components/common/table.js
|
80
|
+
- webpack/__mocks__/foremanReact/constants.js
|
81
|
+
- webpack/__mocks__/foremanReact/redux/API/APISelectors.js
|
82
|
+
- webpack/__mocks__/foremanReact/redux/API/index.js
|
83
|
+
- webpack/__mocks__/foremanReact/redux/actions/common/forms.js
|
84
|
+
- webpack/__mocks__/foremanReact/redux/actions/toasts.js
|
85
|
+
- webpack/__mocks__/foremanReact/routes/common/PageLayout/PageLayout.js
|
86
|
+
- webpack/__mocks__/foremanReact/routes/common/PageLayout/components/ExportButton/ExportButton.js
|
65
87
|
- webpack/global_index.js
|
66
88
|
- webpack/global_test_setup.js
|
67
89
|
- webpack/index.js
|
@@ -87,6 +109,8 @@ files:
|
|
87
109
|
- webpack/src/Router/HostReports/IndexPage/IndexPageActions.js
|
88
110
|
- webpack/src/Router/HostReports/IndexPage/IndexPageHelpers.js
|
89
111
|
- webpack/src/Router/HostReports/IndexPage/IndexPageSelectors.js
|
112
|
+
- webpack/src/Router/HostReports/IndexPage/__tests__/HostReportsIndexPage.test.js
|
113
|
+
- webpack/src/Router/HostReports/IndexPage/__tests__/__snapshots__/HostReportsIndexPage.test.js.snap
|
90
114
|
- webpack/src/Router/HostReports/IndexPage/constants.js
|
91
115
|
- webpack/src/Router/HostReports/IndexPage/index.js
|
92
116
|
- webpack/src/Router/HostReports/ShowPage/Components/HostReportMetrics/HostReportMetrics.scss
|
@@ -101,7 +125,6 @@ files:
|
|
101
125
|
- webpack/src/Router/HostReports/ShowPage/index.js
|
102
126
|
- webpack/src/Router/HostReports/constants.js
|
103
127
|
- webpack/src/Router/routes.js
|
104
|
-
- webpack/test_setup.js
|
105
128
|
homepage: https://github.com/theforeman/foreman_host_reports
|
106
129
|
licenses:
|
107
130
|
- GPL-3.0
|
@@ -131,3 +154,4 @@ test_files:
|
|
131
154
|
- test/controllers/api/v2/host_reports_controller_test.rb
|
132
155
|
- test/snapshots/foreman-web.json
|
133
156
|
- test/test_plugin_helper.rb
|
157
|
+
- webpack/src/Router/HostReports/IndexPage/__tests__/HostReportsIndexPage.test.js
|
data/webpack/test_setup.js
DELETED
@@ -1,17 +0,0 @@
|
|
1
|
-
import 'core-js/shim';
|
2
|
-
import 'regenerator-runtime/runtime';
|
3
|
-
import MutationObserver from '@sheerun/mutationobserver-shim';
|
4
|
-
|
5
|
-
import { configure } from 'enzyme';
|
6
|
-
import Adapter from 'enzyme-adapter-react-16';
|
7
|
-
|
8
|
-
configure({ adapter: new Adapter() });
|
9
|
-
|
10
|
-
// Mocking translation function
|
11
|
-
global.__ = text => text; // eslint-disable-line
|
12
|
-
|
13
|
-
// Mocking locales to prevent unnecessary fallback messages
|
14
|
-
window.locales = { en: { domain: 'app', locale_data: { app: { '': {} } } } };
|
15
|
-
|
16
|
-
// see https://github.com/testing-library/dom-testing-library/releases/tag/v7.0.0
|
17
|
-
window.MutationObserver = MutationObserver;
|