foreman_remote_execution 4.7.0 → 4.8.0
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/.rubocop_todo.yml +1 -0
- data/app/controllers/api/v2/job_invocations_controller.rb +7 -1
- data/app/lib/actions/remote_execution/run_host_job.rb +2 -1
- data/app/lib/actions/remote_execution/run_hosts_job.rb +57 -3
- data/app/mailers/rex_job_mailer.rb +15 -0
- data/app/models/job_invocation.rb +4 -0
- data/app/models/job_invocation_composer.rb +20 -12
- data/app/models/remote_execution_provider.rb +18 -2
- data/app/models/rex_mail_notification.rb +13 -0
- data/app/models/setting/remote_execution.rb +7 -1
- data/app/services/ui_notifications/remote_execution_jobs/base_job_finish.rb +2 -1
- data/app/views/dashboard/_latest-jobs.html.erb +21 -0
- data/app/views/rex_job_mailer/job_finished.html.erb +24 -0
- data/app/views/rex_job_mailer/job_finished.text.erb +9 -0
- data/app/views/template_invocations/show.html.erb +2 -1
- data/db/seeds.d/50-notification_blueprints.rb +14 -0
- data/db/seeds.d/95-mail_notifications.rb +24 -0
- data/foreman_remote_execution.gemspec +1 -1
- data/lib/foreman_remote_execution/engine.rb +1 -0
- data/lib/foreman_remote_execution/version.rb +1 -1
- data/package.json +6 -6
- data/test/functional/api/v2/job_invocations_controller_test.rb +10 -0
- data/test/unit/actions/run_hosts_job_test.rb +99 -4
- data/test/unit/job_invocation_report_template_test.rb +15 -12
- data/test/unit/remote_execution_provider_test.rb +46 -0
- data/webpack/JobWizard/JobWizard.js +53 -20
- data/webpack/JobWizard/JobWizard.scss +33 -4
- data/webpack/JobWizard/JobWizardConstants.js +17 -0
- data/webpack/JobWizard/__tests__/fixtures.js +8 -0
- data/webpack/JobWizard/__tests__/integration.test.js +3 -7
- data/webpack/JobWizard/steps/AdvancedFields/AdvancedFields.js +16 -5
- data/webpack/JobWizard/steps/AdvancedFields/Fields.js +48 -1
- data/webpack/JobWizard/steps/AdvancedFields/__tests__/AdvancedFields.test.js +29 -14
- data/webpack/JobWizard/steps/CategoryAndTemplate/CategoryAndTemplate.js +4 -2
- data/webpack/JobWizard/steps/CategoryAndTemplate/CategoryAndTemplate.test.js +3 -2
- data/webpack/JobWizard/steps/HostsAndInputs/SelectedChips.js +25 -0
- data/webpack/JobWizard/steps/HostsAndInputs/TemplateInputs.js +23 -0
- data/webpack/JobWizard/steps/HostsAndInputs/__tests__/SelectedChips.test.js +37 -0
- data/webpack/JobWizard/steps/HostsAndInputs/__tests__/TemplateInputs.test.js +50 -0
- data/webpack/JobWizard/steps/HostsAndInputs/index.js +66 -0
- data/webpack/JobWizard/steps/Schedule/ScheduleType.js +24 -21
- data/webpack/JobWizard/steps/Schedule/StartEndDates.js +36 -21
- data/webpack/JobWizard/steps/Schedule/__tests__/Schedule.test.js +155 -0
- data/webpack/JobWizard/steps/Schedule/__tests__/StartEndDates.test.js +9 -8
- data/webpack/JobWizard/steps/Schedule/index.js +89 -28
- data/webpack/JobWizard/steps/form/DateTimePicker.js +93 -0
- data/webpack/JobWizard/steps/form/Formatter.js +10 -9
- data/webpack/JobWizard/steps/form/NumberInput.js +2 -0
- data/webpack/JobWizard/steps/form/WizardTitle.js +14 -0
- data/webpack/react_app/components/RecentJobsCard/RecentJobsCard.js +2 -1
- metadata +18 -4
@@ -0,0 +1,24 @@
|
|
1
|
+
N_('Remote execution job')
|
2
|
+
|
3
|
+
notifications = [
|
4
|
+
{
|
5
|
+
:name => 'remote_execution_job',
|
6
|
+
:description => N_('A notification when a job finishes'),
|
7
|
+
:mailer => 'RexJobMailer',
|
8
|
+
:method => 'job_finished',
|
9
|
+
:subscription_type => 'alert',
|
10
|
+
},
|
11
|
+
]
|
12
|
+
|
13
|
+
notifications.each do |notification|
|
14
|
+
if (mail = RexMailNotification.find_by(name: notification[:name]))
|
15
|
+
mail.attributes = notification
|
16
|
+
mail.save! if mail.changed?
|
17
|
+
else
|
18
|
+
created_notification = RexMailNotification.create(notification)
|
19
|
+
if created_notification.nil? || created_notification.errors.any?
|
20
|
+
raise ::Foreman::Exception.new(N_("Unable to create mail notification: %s"),
|
21
|
+
format_errors(created_notification))
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
@@ -24,7 +24,7 @@ Gem::Specification.new do |s|
|
|
24
24
|
|
25
25
|
s.add_dependency 'deface'
|
26
26
|
s.add_dependency 'dynflow', '>= 1.0.2', '< 2.0.0'
|
27
|
-
s.add_dependency 'foreman-tasks', '>= 5.
|
27
|
+
s.add_dependency 'foreman-tasks', '>= 5.1.0'
|
28
28
|
|
29
29
|
s.add_development_dependency 'factory_bot_rails', '~> 4.8.0'
|
30
30
|
s.add_development_dependency 'rdoc'
|
@@ -146,6 +146,7 @@ module ForemanRemoteExecution
|
|
146
146
|
register_custom_status HostStatus::ExecutionStatus
|
147
147
|
# add dashboard widget
|
148
148
|
# widget 'foreman_remote_execution_widget', name: N_('Foreman plugin template widget'), sizex: 4, sizey: 1
|
149
|
+
widget 'dashboard/latest-jobs', :name => N_('Latest Jobs'), :sizex => 6, :sizey => 1
|
149
150
|
|
150
151
|
parameter_filter Subnet, :remote_execution_proxies, :remote_execution_proxy_ids => []
|
151
152
|
parameter_filter Nic::Interface do |ctx|
|
data/package.json
CHANGED
@@ -21,11 +21,11 @@
|
|
21
21
|
},
|
22
22
|
"devDependencies": {
|
23
23
|
"@babel/core": "^7.7.0",
|
24
|
-
"@theforeman/builder": "^
|
25
|
-
"@theforeman/eslint-plugin-foreman": "^
|
26
|
-
"@theforeman/stories": "^
|
27
|
-
"@theforeman/test": "^
|
28
|
-
"@theforeman/vendor-dev": "^
|
24
|
+
"@theforeman/builder": "^8.10.0",
|
25
|
+
"@theforeman/eslint-plugin-foreman": "^8.10.0",
|
26
|
+
"@theforeman/stories": "^8.10.0",
|
27
|
+
"@theforeman/test": "^8.10.0",
|
28
|
+
"@theforeman/vendor-dev": "^8.10.0",
|
29
29
|
"babel-eslint": "^10.0.0",
|
30
30
|
"eslint": "^6.8.0",
|
31
31
|
"prettier": "^1.19.1",
|
@@ -33,6 +33,6 @@
|
|
33
33
|
"redux-mock-store": "^1.2.2"
|
34
34
|
},
|
35
35
|
"peerDependencies": {
|
36
|
-
"@theforeman/vendor": "^8.
|
36
|
+
"@theforeman/vendor": "^8.10.0"
|
37
37
|
}
|
38
38
|
}
|
@@ -90,6 +90,16 @@ module Api
|
|
90
90
|
assert_response :success
|
91
91
|
end
|
92
92
|
|
93
|
+
test 'should create with a scheduled recurrence' do
|
94
|
+
@attrs[:scheduling] = { start_at: (Time.now + 1.hour) }
|
95
|
+
@attrs[:recurrence] = { cron_line: '5 * * * *' }
|
96
|
+
post :create, params: { job_invocation: @attrs }
|
97
|
+
invocation = ActiveSupport::JSON.decode(@response.body)
|
98
|
+
assert_equal 'recurring', invocation['mode']
|
99
|
+
assert invocation['start_at']
|
100
|
+
assert_response :success
|
101
|
+
end
|
102
|
+
|
93
103
|
context 'with_feature' do
|
94
104
|
setup do
|
95
105
|
@feature = FactoryBot.create(:remote_execution_feature,
|
@@ -5,6 +5,16 @@ module ForemanRemoteExecution
|
|
5
5
|
class RunHostsJobTest < ActiveSupport::TestCase
|
6
6
|
include Dynflow::Testing
|
7
7
|
|
8
|
+
# Adding run_step_id wich is needed in RunHostsJob as a quick fix
|
9
|
+
# it will be added to dynflow in the future see https://github.com/Dynflow/dynflow/pull/391
|
10
|
+
# rubocop:disable Style/ClassAndModuleChildren
|
11
|
+
class Dynflow::Testing::DummyPlannedAction
|
12
|
+
def run_step_id
|
13
|
+
Dynflow::Testing.get_id
|
14
|
+
end
|
15
|
+
end
|
16
|
+
# rubocop:enable Style/ClassAndModuleChildren
|
17
|
+
|
8
18
|
let(:host) { FactoryBot.create(:host, :with_execution) }
|
9
19
|
let(:proxy) { host.remote_execution_proxies('SSH')[:subnet].first }
|
10
20
|
let(:targeting) { FactoryBot.create(:targeting, :search_query => "name = #{host.name}", :user => User.current) }
|
@@ -94,6 +104,22 @@ module ForemanRemoteExecution
|
|
94
104
|
planned # To make the expectations happy
|
95
105
|
end
|
96
106
|
|
107
|
+
describe '#proxy_batch_size' do
|
108
|
+
it 'defaults to Setting[foreman_tasks_proxy_batch_size]' do
|
109
|
+
Setting.expects(:[]).with('foreman_tasks_proxy_batch_size').returns(14)
|
110
|
+
planned
|
111
|
+
_(planned.proxy_batch_size).must_equal 14
|
112
|
+
end
|
113
|
+
|
114
|
+
it 'gets the provider value' do
|
115
|
+
provider = mock('provider')
|
116
|
+
provider.expects(:proxy_batch_size).returns(15)
|
117
|
+
JobTemplate.any_instance.expects(:provider).returns(provider)
|
118
|
+
|
119
|
+
_(planned.proxy_batch_size).must_equal 15
|
120
|
+
end
|
121
|
+
end
|
122
|
+
|
97
123
|
describe 'concurrency control' do
|
98
124
|
let(:level) { 5 }
|
99
125
|
let(:span) { 60 }
|
@@ -127,10 +153,79 @@ module ForemanRemoteExecution
|
|
127
153
|
end
|
128
154
|
|
129
155
|
describe 'notifications' do
|
130
|
-
it 'creates notification on
|
131
|
-
|
132
|
-
|
133
|
-
|
156
|
+
it 'creates drawer notification on succeess' do
|
157
|
+
blueprint = planned.job_invocation.build_notification
|
158
|
+
blueprint.expects(:deliver!)
|
159
|
+
planned.job_invocation.expects(:build_notification).returns(blueprint)
|
160
|
+
planned.notify_on_success(nil)
|
161
|
+
end
|
162
|
+
|
163
|
+
it 'creates drawer notification on failure' do
|
164
|
+
blueprint = planned.job_invocation.build_notification
|
165
|
+
blueprint.expects(:deliver!)
|
166
|
+
planned.job_invocation.expects(:build_notification).returns(blueprint)
|
167
|
+
planned.notify_on_failure(nil)
|
168
|
+
end
|
169
|
+
|
170
|
+
describe 'ignoring drawer notification' do
|
171
|
+
before do
|
172
|
+
blueprint = planned.job_invocation.build_notification
|
173
|
+
blueprint.expects(:deliver!)
|
174
|
+
planned.job_invocation.expects(:build_notification).returns(blueprint)
|
175
|
+
end
|
176
|
+
|
177
|
+
let(:mail) do
|
178
|
+
object = mock
|
179
|
+
object.stubs(:deliver_now)
|
180
|
+
object
|
181
|
+
end
|
182
|
+
|
183
|
+
describe 'for user subscribed to all' do
|
184
|
+
before do
|
185
|
+
planned.expects(:mail_notification_preference).returns(UserMailNotification.new(:interval => RexMailNotification::ALL_JOBS))
|
186
|
+
end
|
187
|
+
|
188
|
+
it 'sends the mail notification on success' do
|
189
|
+
RexJobMailer.expects(:job_finished).returns(mail)
|
190
|
+
planned.notify_on_success(nil)
|
191
|
+
end
|
192
|
+
|
193
|
+
it 'sends the mail notification on failure' do
|
194
|
+
RexJobMailer.expects(:job_finished).returns(mail)
|
195
|
+
planned.notify_on_failure(nil)
|
196
|
+
end
|
197
|
+
end
|
198
|
+
|
199
|
+
describe 'for user subscribed to failures' do
|
200
|
+
before do
|
201
|
+
planned.expects(:mail_notification_preference).returns(UserMailNotification.new(:interval => RexMailNotification::FAILED_JOBS))
|
202
|
+
end
|
203
|
+
|
204
|
+
it 'it does not send the mail notification on success' do
|
205
|
+
RexJobMailer.expects(:job_finished).never
|
206
|
+
planned.notify_on_success(nil)
|
207
|
+
end
|
208
|
+
|
209
|
+
it 'sends the mail notification on failure' do
|
210
|
+
RexJobMailer.expects(:job_finished).returns(mail)
|
211
|
+
planned.notify_on_failure(nil)
|
212
|
+
end
|
213
|
+
end
|
214
|
+
|
215
|
+
describe 'for user subscribed to successful jobs' do
|
216
|
+
before do
|
217
|
+
planned.expects(:mail_notification_preference).returns(UserMailNotification.new(:interval => RexMailNotification::SUCCEEDED_JOBS))
|
218
|
+
end
|
219
|
+
|
220
|
+
it 'sends the mail notification on success' do
|
221
|
+
RexJobMailer.expects(:job_finished).returns(mail)
|
222
|
+
planned.notify_on_success(nil)
|
223
|
+
end
|
224
|
+
|
225
|
+
it 'does not send the mail notification on failure' do
|
226
|
+
RexJobMailer.expects(:job_finished).never
|
227
|
+
planned.notify_on_failure(nil)
|
228
|
+
end
|
134
229
|
end
|
135
230
|
end
|
136
231
|
end
|
@@ -28,15 +28,16 @@ class JobReportTemplateTest < ActiveSupport::TestCase
|
|
28
28
|
describe 'task reporting' do
|
29
29
|
let(:fake_outputs) do
|
30
30
|
[
|
31
|
-
{ 'output_type' => 'stderr', 'output' => "error"
|
32
|
-
{ 'output_type' => 'stdout', 'output' => "output"
|
33
|
-
{ 'output_type' => '
|
31
|
+
{ 'output_type' => 'stderr', 'output' => "error" },
|
32
|
+
{ 'output_type' => 'stdout', 'output' => "output" },
|
33
|
+
{ 'output_type' => 'debug', 'output' => "debug" },
|
34
34
|
]
|
35
35
|
end
|
36
|
-
let(:fake_task) { FakeTask.new(result: 'success', action_continuous_output: fake_outputs) }
|
36
|
+
let(:fake_task) { FakeTask.new(result: 'success', action_continuous_output: fake_outputs, :ended_at => Time.new(2020, 12, 1, 0, 0, 0).utc) }
|
37
|
+
let(:job_invocation) { FactoryBot.create(:job_invocation, :with_task) }
|
38
|
+
let(:host) { job_invocation.template_invocations.first.host }
|
37
39
|
|
38
40
|
it 'should render task outputs' do
|
39
|
-
job_invocation = FactoryBot.create(:job_invocation, :with_task)
|
40
41
|
JobInvocation.any_instance.expects(:sub_task_for_host).returns(fake_task)
|
41
42
|
|
42
43
|
input = job_invocation_template.template_inputs.first
|
@@ -44,13 +45,15 @@ class JobReportTemplateTest < ActiveSupport::TestCase
|
|
44
45
|
result = ReportComposer.new(composer_params).render
|
45
46
|
|
46
47
|
# parsing the CSV result
|
47
|
-
CSV.parse(result.strip, headers: true)
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
48
|
+
rows = CSV.parse(result.strip, headers: true)
|
49
|
+
assert_equal 1, rows.count
|
50
|
+
row = rows.first
|
51
|
+
assert_equal host.name, row['Host']
|
52
|
+
assert_equal 'success', row['Result']
|
53
|
+
assert_equal 'error', row['stderr']
|
54
|
+
assert_equal 'output', row['stdout']
|
55
|
+
assert_equal 'debug', row['debug']
|
56
|
+
assert_kind_of Time, Time.zone.parse(row['Finished']), 'Parsing of time column failed'
|
54
57
|
end
|
55
58
|
end
|
56
59
|
end
|
@@ -50,6 +50,18 @@ class RemoteExecutionProviderTest < ActiveSupport::TestCase
|
|
50
50
|
end
|
51
51
|
end
|
52
52
|
|
53
|
+
describe '.host_setting' do
|
54
|
+
let(:host) { FactoryBot.create(:host) }
|
55
|
+
|
56
|
+
it 'honors falsey values set as a host parameter' do
|
57
|
+
key = 'remote_execution_connect_by_ip'
|
58
|
+
Setting[key] = true
|
59
|
+
host.parameters << HostParameter.new(name: key, value: false)
|
60
|
+
|
61
|
+
refute RemoteExecutionProvider.host_setting(host, key)
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
53
65
|
describe SSHExecutionProvider do
|
54
66
|
before { User.current = FactoryBot.build(:user, :admin) }
|
55
67
|
after { User.current = nil }
|
@@ -200,6 +212,40 @@ class RemoteExecutionProviderTest < ActiveSupport::TestCase
|
|
200
212
|
host.interfaces.each(&:save)
|
201
213
|
host.reload
|
202
214
|
SSHExecutionProvider.find_ip_or_hostname(host).must_equal execution_interface.ip
|
215
|
+
|
216
|
+
# there is an execution interface with both IPv6 and IPv4: IPv4 is being preferred over IPv6 by default
|
217
|
+
execution_interface = FactoryBot.build(:nic_managed,
|
218
|
+
flags.merge(:execution => true, :ip => '10.0.0.4', :ip6 => 'fd00::4'))
|
219
|
+
host.interfaces = [execution_interface]
|
220
|
+
host.interfaces.each(&:save)
|
221
|
+
host.reload
|
222
|
+
SSHExecutionProvider.find_ip_or_hostname(host).must_equal execution_interface.ip
|
223
|
+
end
|
224
|
+
|
225
|
+
it 'gets ipv6 from flagged interfaces with IPv6 preference' do
|
226
|
+
host.host_params['remote_execution_connect_by_ip_prefer_ipv6'] = true
|
227
|
+
host.host_params['remote_execution_connect_by_ip'] = true
|
228
|
+
|
229
|
+
# there is an execution interface with both IPv6 and IPv4: IPv6 is being preferred over IPv4 by host parameter configuration
|
230
|
+
execution_interface = FactoryBot.build(:nic_managed,
|
231
|
+
flags.merge(:execution => true, :ip => '10.0.0.4', :ip6 => 'fd00::4'))
|
232
|
+
host.interfaces = [execution_interface]
|
233
|
+
host.interfaces.each(&:save)
|
234
|
+
host.reload
|
235
|
+
SSHExecutionProvider.find_ip_or_hostname(host).must_equal execution_interface.ip6
|
236
|
+
end
|
237
|
+
|
238
|
+
it 'gets ipv6 from flagged interfaces with IPv4 preference but without IPv4 address' do
|
239
|
+
host.host_params['remote_execution_connect_by_ip_prefer_ipv6'] = false
|
240
|
+
host.host_params['remote_execution_connect_by_ip'] = true
|
241
|
+
|
242
|
+
# there is an execution interface with both IPv6 and IPv4: IPv6 is being preferred over IPv4 by host parameter configuration
|
243
|
+
execution_interface = FactoryBot.build(:nic_managed,
|
244
|
+
flags.merge(:execution => true, :ip => nil, :ip6 => 'fd00::4'))
|
245
|
+
host.interfaces = [execution_interface]
|
246
|
+
host.interfaces.each(&:save)
|
247
|
+
host.reload
|
248
|
+
SSHExecutionProvider.find_ip_or_hostname(host).must_equal execution_interface.ip6
|
203
249
|
end
|
204
250
|
end
|
205
251
|
end
|
@@ -3,43 +3,64 @@ import React, { useState, useEffect, useCallback } from 'react';
|
|
3
3
|
import { useDispatch, useSelector } from 'react-redux';
|
4
4
|
import { Wizard } from '@patternfly/react-core';
|
5
5
|
import { get } from 'foremanReact/redux/API';
|
6
|
-
import { translate as __ } from 'foremanReact/common/I18n';
|
7
6
|
import history from 'foremanReact/history';
|
8
7
|
import CategoryAndTemplate from './steps/CategoryAndTemplate/';
|
9
8
|
import { AdvancedFields } from './steps/AdvancedFields/AdvancedFields';
|
10
|
-
import {
|
9
|
+
import {
|
10
|
+
JOB_TEMPLATE,
|
11
|
+
WIZARD_TITLES,
|
12
|
+
initialScheduleState,
|
13
|
+
} from './JobWizardConstants';
|
11
14
|
import { selectTemplateError } from './JobWizardSelectors';
|
12
15
|
import Schedule from './steps/Schedule/';
|
16
|
+
import HostsAndInputs from './steps/HostsAndInputs/';
|
13
17
|
import './JobWizard.scss';
|
14
18
|
|
15
19
|
export const JobWizard = () => {
|
16
20
|
const [jobTemplateID, setJobTemplateID] = useState(null);
|
17
21
|
const [category, setCategory] = useState('');
|
18
22
|
const [advancedValues, setAdvancedValues] = useState({});
|
23
|
+
const [templateValues, setTemplateValues] = useState({}); // TODO use templateValues in advanced fields - description https://github.com/theforeman/foreman_remote_execution/pull/605
|
24
|
+
const [selectedHosts, setSelectedHosts] = useState(['host1', 'host2']);
|
25
|
+
const [scheduleValue, setScheduleValue] = useState(initialScheduleState);
|
19
26
|
const dispatch = useDispatch();
|
20
27
|
|
21
28
|
const setDefaults = useCallback(
|
22
29
|
({
|
23
30
|
data: {
|
31
|
+
template_inputs,
|
24
32
|
advanced_template_inputs,
|
25
33
|
effective_user,
|
26
|
-
job_template: {
|
34
|
+
job_template: { execution_timeout_interval, description_format },
|
27
35
|
},
|
28
36
|
}) => {
|
29
37
|
const advancedTemplateValues = {};
|
38
|
+
const defaultTemplateValues = {};
|
39
|
+
const inputs = template_inputs;
|
30
40
|
const advancedInputs = advanced_template_inputs;
|
31
|
-
if (
|
32
|
-
|
33
|
-
|
41
|
+
if (inputs) {
|
42
|
+
setTemplateValues(() => {
|
43
|
+
inputs.forEach(input => {
|
44
|
+
defaultTemplateValues[input.name] = input?.default || '';
|
45
|
+
});
|
46
|
+
return defaultTemplateValues;
|
34
47
|
});
|
35
48
|
}
|
36
|
-
setAdvancedValues(currentAdvancedValues =>
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
49
|
+
setAdvancedValues(currentAdvancedValues => {
|
50
|
+
if (advancedInputs) {
|
51
|
+
advancedInputs.forEach(input => {
|
52
|
+
advancedTemplateValues[input.name] = input?.default || '';
|
53
|
+
});
|
54
|
+
}
|
55
|
+
return {
|
56
|
+
...currentAdvancedValues,
|
57
|
+
effectiveUserValue: effective_user?.value || '',
|
58
|
+
timeoutToKill: execution_timeout_interval || '',
|
59
|
+
templateValues: advancedTemplateValues,
|
60
|
+
description: description_format || '',
|
61
|
+
isRandomizedOrdering: false,
|
62
|
+
};
|
63
|
+
});
|
43
64
|
},
|
44
65
|
[]
|
45
66
|
);
|
@@ -59,7 +80,7 @@ export const JobWizard = () => {
|
|
59
80
|
const isTemplate = !templateError && !!jobTemplateID;
|
60
81
|
const steps = [
|
61
82
|
{
|
62
|
-
name:
|
83
|
+
name: WIZARD_TITLES.categoryAndTemplate,
|
63
84
|
component: (
|
64
85
|
<CategoryAndTemplate
|
65
86
|
jobTemplate={jobTemplateID}
|
@@ -70,12 +91,19 @@ export const JobWizard = () => {
|
|
70
91
|
),
|
71
92
|
},
|
72
93
|
{
|
73
|
-
name:
|
74
|
-
component:
|
94
|
+
name: WIZARD_TITLES.hostsAndInputs,
|
95
|
+
component: (
|
96
|
+
<HostsAndInputs
|
97
|
+
templateValues={templateValues}
|
98
|
+
setTemplateValues={setTemplateValues}
|
99
|
+
selectedHosts={selectedHosts}
|
100
|
+
setSelectedHosts={setSelectedHosts}
|
101
|
+
/>
|
102
|
+
),
|
75
103
|
canJumpTo: isTemplate,
|
76
104
|
},
|
77
105
|
{
|
78
|
-
name:
|
106
|
+
name: WIZARD_TITLES.advanced,
|
79
107
|
component: (
|
80
108
|
<AdvancedFields
|
81
109
|
advancedValues={advancedValues}
|
@@ -91,12 +119,17 @@ export const JobWizard = () => {
|
|
91
119
|
canJumpTo: isTemplate,
|
92
120
|
},
|
93
121
|
{
|
94
|
-
name:
|
95
|
-
component:
|
122
|
+
name: WIZARD_TITLES.schedule,
|
123
|
+
component: (
|
124
|
+
<Schedule
|
125
|
+
scheduleValue={scheduleValue}
|
126
|
+
setScheduleValue={setScheduleValue}
|
127
|
+
/>
|
128
|
+
),
|
96
129
|
canJumpTo: isTemplate,
|
97
130
|
},
|
98
131
|
{
|
99
|
-
name:
|
132
|
+
name: WIZARD_TITLES.review,
|
100
133
|
component: <p>Review Details</p>,
|
101
134
|
nextButtonText: 'Run',
|
102
135
|
canJumpTo: isTemplate,
|