foreman_remote_execution 4.3.1 → 4.4.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (67) hide show
  1. checksums.yaml +4 -4
  2. data/app/controllers/api/v2/job_invocations_controller.rb +16 -0
  3. data/app/controllers/foreman_remote_execution/concerns/api/v2/registration_commands_controller_extensions.rb +19 -0
  4. data/app/helpers/remote_execution_helper.rb +27 -0
  5. data/app/lib/foreman_remote_execution/provider_input.rb +29 -0
  6. data/app/models/invocation_provider_input_value.rb +12 -0
  7. data/app/models/job_invocation.rb +4 -0
  8. data/app/models/job_invocation_composer.rb +13 -0
  9. data/app/models/remote_execution_provider.rb +17 -2
  10. data/app/models/setting/remote_execution.rb +10 -0
  11. data/app/models/template_invocation.rb +2 -0
  12. data/app/services/renderer_methods.rb +12 -0
  13. data/app/views/job_invocations/_form.html.erb +8 -0
  14. data/db/migrate/20210312074713_add_provider_inputs.rb +10 -0
  15. data/foreman_remote_execution.gemspec +1 -1
  16. data/lib/foreman_remote_execution/engine.rb +5 -6
  17. data/lib/foreman_remote_execution/version.rb +1 -1
  18. data/locale/action_names.rb +1 -0
  19. data/locale/de/foreman_remote_execution.po +77 -27
  20. data/locale/en/foreman_remote_execution.po +77 -27
  21. data/locale/en_GB/foreman_remote_execution.po +77 -27
  22. data/locale/es/foreman_remote_execution.po +77 -27
  23. data/locale/foreman_remote_execution.pot +241 -163
  24. data/locale/fr/foreman_remote_execution.po +77 -27
  25. data/locale/ja/foreman_remote_execution.po +77 -27
  26. data/locale/ko/foreman_remote_execution.po +77 -27
  27. data/locale/pt_BR/foreman_remote_execution.po +77 -27
  28. data/locale/ru/foreman_remote_execution.po +77 -27
  29. data/locale/zh_CN/foreman_remote_execution.po +77 -27
  30. data/locale/zh_TW/foreman_remote_execution.po +77 -27
  31. data/package.json +3 -2
  32. data/test/helpers/remote_execution_helper_test.rb +16 -0
  33. data/test/unit/job_invocation_composer_test.rb +41 -1
  34. data/test/unit/job_invocation_report_template_test.rb +57 -0
  35. data/webpack/JobWizard/JobWizard.js +30 -7
  36. data/webpack/JobWizard/JobWizard.scss +12 -0
  37. data/webpack/JobWizard/JobWizardConstants.js +5 -0
  38. data/webpack/JobWizard/JobWizardSelectors.js +21 -0
  39. data/webpack/JobWizard/__tests__/JobWizard.test.js +20 -0
  40. data/webpack/JobWizard/__tests__/__snapshots__/JobWizard.test.js.snap +83 -0
  41. data/webpack/JobWizard/steps/CategoryAndTemplate/CategoryAndTemplate.js +77 -0
  42. data/webpack/JobWizard/steps/CategoryAndTemplate/CategoryAndTemplate.test.js +45 -0
  43. data/webpack/JobWizard/steps/CategoryAndTemplate/__snapshots__/CategoryAndTemplate.test.js.snap +64 -0
  44. data/webpack/JobWizard/steps/CategoryAndTemplate/index.js +86 -0
  45. data/webpack/JobWizard/steps/form/GroupedSelectField.js +88 -0
  46. data/webpack/JobWizard/steps/form/SelectField.js +39 -0
  47. data/webpack/JobWizard/steps/form/__tests__/GroupedSelectField.test.js +38 -0
  48. data/webpack/JobWizard/steps/form/__tests__/SelectField.test.js +23 -0
  49. data/webpack/JobWizard/steps/form/__tests__/__snapshots__/GroupedSelectField.test.js.snap +36 -0
  50. data/webpack/JobWizard/steps/form/__tests__/__snapshots__/SelectField.test.js.snap +22 -0
  51. data/webpack/__mocks__/foremanReact/common/helpers.js +1 -0
  52. data/webpack/__mocks__/foremanReact/redux/API/index.js +5 -0
  53. data/webpack/__mocks__/foremanReact/routes/common/PageLayout/PageLayout.js +10 -0
  54. data/webpack/fills_index.js +11 -0
  55. data/webpack/global_index.js +4 -0
  56. data/webpack/index.js +0 -4
  57. data/webpack/react_app/components/RecentJobsCard/RecentJobsCard.js +87 -0
  58. data/webpack/react_app/components/RecentJobsCard/constants.js +1 -0
  59. data/webpack/react_app/components/RecentJobsCard/index.js +1 -0
  60. data/webpack/react_app/components/RecentJobsCard/styles.css +15 -0
  61. data/webpack/react_app/components/RegistrationExtension/RexInterface.js +50 -0
  62. data/webpack/react_app/components/RegistrationExtension/__tests__/RexInterface.test.js +9 -0
  63. data/webpack/react_app/components/RegistrationExtension/__tests__/__snapshots__/RexInterface.test.js.snap +35 -0
  64. data/webpack/react_app/extend/fills.js +10 -0
  65. data/webpack/react_app/extend/reducers.js +4 -0
  66. metadata +39 -5
  67. data/app/views/api/v2/registration/_form.html.erb +0 -12
@@ -26,6 +26,11 @@ msgstr "%s 之前"
26
26
  msgid "%{description} on %{host}"
27
27
  msgstr "%{description} 於 %{host} 之上"
28
28
 
29
+ msgid "...and %{count} more"
30
+ msgid_plural "...and %{count} more"
31
+ msgstr[0] ""
32
+ msgstr[1] ""
33
+
29
34
  msgid "A comma separated list of input names to be excluded from the foreign template."
30
35
  msgstr "從外部範本排除的輸入名稱清單,以逗號隔開。"
31
36
 
@@ -53,6 +58,12 @@ msgstr "動作"
53
58
  msgid "Add Foreign Input Set"
54
59
  msgstr "新增外部輸入集"
55
60
 
61
+ msgid "Advanced fields"
62
+ msgstr ""
63
+
64
+ msgid "All fields are required."
65
+ msgstr ""
66
+
56
67
  msgid "Alphabetical"
57
68
  msgstr ""
58
69
 
@@ -95,6 +106,12 @@ msgstr "無法指定 bookmark_id 和 search_query"
95
106
  msgid "Cannot specify both recurrence and scheduling"
96
107
  msgstr "無法指定 recurrence 和 scheduling"
97
108
 
109
+ msgid "Category And Template"
110
+ msgstr ""
111
+
112
+ msgid "Category and template"
113
+ msgstr ""
114
+
98
115
  msgid "Choose a job template that is pre-selected in job invocation form"
99
116
  msgstr ""
100
117
 
@@ -125,6 +142,9 @@ msgstr ""
125
142
  msgid "Control concurrency level and distribution over time"
126
143
  msgstr "隨時間控制週期等級並散佈"
127
144
 
145
+ msgid "Could not display data for job invocation."
146
+ msgstr ""
147
+
128
148
  msgid "Could not find any suitable interface for execution"
129
149
  msgstr ""
130
150
 
@@ -227,6 +247,12 @@ msgstr "有效使用者方法 \"%{current_value}\" 並非 %{valid_methods} 之
227
247
  msgid "Effective user options"
228
248
  msgstr "有效的使用者選項"
229
249
 
250
+ msgid "Effective user password"
251
+ msgstr ""
252
+
253
+ msgid "Effective user password is only applicable for SSH provider. Other providers ignore this field. <br> Password is stored encrypted in DB until the job finishes. For future or recurring executions, it is removed after the last execution."
254
+ msgstr ""
255
+
230
256
  msgid "Enable Global Proxy"
231
257
  msgstr ""
232
258
 
@@ -263,18 +289,12 @@ msgstr "已失敗"
263
289
  msgid "Failed rendering template: %s"
264
290
  msgstr "無法生成範本:%s"
265
291
 
266
- msgid "Fallback Without Proxy"
267
- msgstr ""
268
-
269
292
  msgid "Fallback to Any Proxy"
270
293
  msgstr ""
271
294
 
272
295
  msgid "Feature input %{input_name} not defined in template %{template_name}"
273
296
  msgstr "未知的輸入 %{input_name} 未定義於範本 %{template_name}"
274
297
 
275
- msgid "Filter"
276
- msgstr "篩選器"
277
-
278
298
  msgid "Foreign input set"
279
299
  msgstr "外部輸入集"
280
300
 
@@ -287,6 +307,9 @@ msgstr ""
287
307
  msgid "Get output for a host"
288
308
  msgstr "取得主機輸出"
289
309
 
310
+ msgid "Get outputs of hosts in a job"
311
+ msgstr ""
312
+
290
313
  msgid "Get raw output for a host"
291
314
  msgstr ""
292
315
 
@@ -305,9 +328,15 @@ msgstr ""
305
328
  msgid "Host with id '%{id}' was not found"
306
329
  msgstr "找不到 ID 為 '%{id}' 的主機"
307
330
 
331
+ msgid "Hosts gone missing"
332
+ msgstr ""
333
+
308
334
  msgid "How often the job should occur, in the cron format"
309
335
  msgstr "工作多常發生,格式同 cron"
310
336
 
337
+ msgid "Identifier of the Host interface for Remote execution"
338
+ msgstr ""
339
+
311
340
  msgid "Import"
312
341
  msgstr "匯入"
313
342
 
@@ -335,6 +364,12 @@ msgstr "輸入集的描述"
335
364
  msgid "Inputs to use"
336
365
  msgstr "要使用的輸入"
337
366
 
367
+ msgid "Interface with the '%s' identifier was specified as a remote execution interface, however the interface was not found on the host. If the interface exists, it needs to be created in Foreman during the registration."
368
+ msgstr ""
369
+
370
+ msgid "Internal proxy selector can only be used if Katello is enabled"
371
+ msgstr ""
372
+
338
373
  msgid "Invocation type, one of %s"
339
374
  msgstr "祈願類型,%s 之一"
340
375
 
@@ -386,6 +421,9 @@ msgstr ""
386
421
  msgid "Job templates"
387
422
  msgstr "工作範本"
388
423
 
424
+ msgid "Job wizard"
425
+ msgstr ""
426
+
389
427
  msgid "JobTemplate|Locked"
390
428
  msgstr "JobTemplate|Locked"
391
429
 
@@ -431,6 +469,9 @@ msgstr "列出各個位置上的工作範本"
431
469
  msgid "List job templates per organization"
432
470
  msgstr "列出各個組織的工作範本"
433
471
 
472
+ msgid "List of proxy IDs to be used for remote execution"
473
+ msgstr ""
474
+
434
475
  msgid "List remote execution features"
435
476
  msgstr "列出遠端執行功能"
436
477
 
@@ -458,6 +499,9 @@ msgstr "新工作範本"
458
499
  msgid "No execution finished yet"
459
500
  msgstr "尚無執行完成"
460
501
 
502
+ msgid "No hosts found."
503
+ msgstr ""
504
+
461
505
  msgid "No template mapped to feature %{feature_name}"
462
506
  msgstr "沒有範本定義至功能 %{feature_name}"
463
507
 
@@ -500,6 +544,9 @@ msgstr "此時間之後不再進行任何執行"
500
544
  msgid "Port to use for SSH communication. Default port 22. You may override per host by setting a parameter called remote_execution_ssh_port."
501
545
  msgstr ""
502
546
 
547
+ msgid "Preupgrade job"
548
+ msgstr ""
549
+
503
550
  msgid "Preview"
504
551
  msgstr "預覽"
505
552
 
@@ -539,6 +586,9 @@ msgstr "遠端執行"
539
586
  msgid "Remote Execution Features"
540
587
  msgstr "遠端執行功能"
541
588
 
589
+ msgid "Remote Execution Interface"
590
+ msgstr ""
591
+
542
592
  msgid "Remote action:"
543
593
  msgstr "遠端動作:"
544
594
 
@@ -578,6 +628,9 @@ msgstr "解析至"
578
628
  msgid "Results"
579
629
  msgstr ""
580
630
 
631
+ msgid "Review details"
632
+ msgstr ""
633
+
581
634
  msgid "Run"
582
635
  msgstr "執行"
583
636
 
@@ -593,6 +646,9 @@ msgstr "一次最多執行 N 個任務"
593
646
  msgid "Run at most N tasks at a time. If this is set and proxy batch triggering is enabled, then tasks are triggered on the smart proxy in batches of size 1."
594
647
  msgstr ""
595
648
 
649
+ msgid "Run job"
650
+ msgstr ""
651
+
596
652
  msgid "SSH"
597
653
  msgstr "SSH"
598
654
 
@@ -629,9 +685,6 @@ msgstr "捲動至底端"
629
685
  msgid "Scroll to top"
630
686
  msgstr "捲動至頂端"
631
687
 
632
- msgid "Search"
633
- msgstr "搜尋"
634
-
635
688
  msgid "Search Query"
636
689
  msgstr ""
637
690
 
@@ -659,6 +712,12 @@ msgstr ""
659
712
  msgid "Should the ip addresses on host interfaces be preferred over the fqdn? It is useful when DNS not resolving the fqdns properly. You may override this per host by setting a parameter called remote_execution_connect_by_ip. This setting only applies to IPv4. When the host has only an IPv6 address on the interface used for remote execution, hostname will be used even if this setting is set to true."
660
713
  msgstr ""
661
714
 
715
+ msgid "Should this interface be used for remote execution?"
716
+ msgstr ""
717
+
718
+ msgid "Show Job status for the hosts"
719
+ msgstr ""
720
+
662
721
  msgid "Show foreign input set details"
663
722
  msgstr "顯示外部輸入集的詳細資料"
664
723
 
@@ -689,12 +748,6 @@ msgstr "已成功"
689
748
  msgid "Success"
690
749
  msgstr "成功"
691
750
 
692
- msgid "Sudo password"
693
- msgstr ""
694
-
695
- msgid "Sudo password is only applicable for SSH provider. Other providers ignore this field. <br> Password is stored encrypted in DB until the job finishes. For future or recurring executions, it is removed after the last execution."
696
- msgstr ""
697
-
698
751
  msgid "Sync Job Templates"
699
752
  msgstr ""
700
753
 
@@ -760,6 +813,9 @@ msgstr "使用者無法存取範本 %{template_name} 對應至功能 %{feature_n
760
813
  msgid "There was an error while updating the status, try refreshing the page."
761
814
  msgstr "更新狀態時發生錯誤,請更新此頁面。"
762
815
 
816
+ msgid "This can happen if the host is removed or moved to another organization or location after the job was started"
817
+ msgstr ""
818
+
763
819
  msgid "This template is locked for editing."
764
820
  msgstr "此範本已鎖定,因此無法編輯。"
765
821
 
@@ -886,9 +942,6 @@ msgstr "哪位使用者該用來執行此 script(使用類似 sudo 機制)"
886
942
  msgid "What user should be used to run the script (using sudo-like mechanisms). Defaults to a template parameter or global setting."
887
943
  msgstr "哪位使用者該用來執行此 script(使用類似 sudo 機制)。預設值設為範本參數或全域設定。"
888
944
 
889
- msgid "When enabled, the remote execution will try to run the commands directly, when no proxy with remote execution feature is configured for the host."
890
- msgstr ""
891
-
892
945
  msgid "When enabled, working directories will be removed after task completion. You may override this per host by setting a parameter called remote_execution_cleanup_working_dirs."
893
946
  msgstr ""
894
947
 
@@ -922,9 +975,15 @@ msgstr "為此範本新增輸入集,以參照至不同的範本輸入"
922
975
  msgid "cancelled"
923
976
  msgstr "已取消"
924
977
 
978
+ msgid "default_capsule method missing from SmartProxy"
979
+ msgstr ""
980
+
925
981
  msgid "effective user"
926
982
  msgstr ""
927
983
 
984
+ msgid "error"
985
+ msgstr ""
986
+
928
987
  msgid "error during rendering: %s"
929
988
  msgstr "處理時發生錯誤:%s"
930
989
 
@@ -949,9 +1008,6 @@ msgstr "找不到包含的範本 '%s'"
949
1008
  msgid "input macro with name '%s' used, but no input with such name defined for this template"
950
1009
  msgstr "使用了名為 '%s' 的輸入巨集,但此範本並未輸入這樣的名稱"
951
1010
 
952
- msgid "planned"
953
- msgstr ""
954
-
955
1011
  msgid "queued"
956
1012
  msgstr "已排程"
957
1013
 
@@ -961,9 +1017,6 @@ msgstr ""
961
1017
  msgid "remove template input set"
962
1018
  msgstr "移除範本輸入集"
963
1019
 
964
- msgid "running"
965
- msgstr "執行中"
966
-
967
1020
  msgid "running %{percent}%%"
968
1021
  msgstr ""
969
1022
 
@@ -973,9 +1026,6 @@ msgstr "秒"
973
1026
  msgid "succeeded"
974
1027
  msgstr "已成功"
975
1028
 
976
- msgid "success"
977
- msgstr "成功"
978
-
979
1029
  msgid "tasks at a time"
980
1030
  msgstr ""
981
1031
 
data/package.json CHANGED
@@ -28,9 +28,10 @@
28
28
  "@theforeman/vendor-dev": "^4.14.0",
29
29
  "babel-eslint": "^10.0.0",
30
30
  "eslint": "^6.8.0",
31
- "prettier": "^1.19.1"
31
+ "prettier": "^1.19.1",
32
+ "@patternfly/react-catalog-view-extension": "^4.8.126"
32
33
  },
33
34
  "peerDependencies": {
34
- "@theforeman/vendor": ">= 4.14.0"
35
+ "@theforeman/vendor": "^8.3.0"
35
36
  }
36
37
  }
@@ -23,4 +23,20 @@ class RemoteExecutionHelperTest < ActionView::TestCase
23
23
  "Exit status: 0"])
24
24
  end
25
25
  end
26
+
27
+ describe 'test correct setting' do
28
+ it 'should found correct template from setting' do
29
+ Setting::RemoteExecution.load_defaults
30
+ template_name = 'Job Invocation Report Template'
31
+ setting_key = 'remote_execution_job_invocation_report_template'
32
+ template = FactoryBot.create(:report_template, name: template_name)
33
+ input = FactoryBot.create(:template_input, name: 'job_id', input_type: 'user')
34
+ template.template_inputs << input
35
+ Setting.expects(:[]).with(setting_key).returns(template_name)
36
+
37
+ found_template = job_report_template
38
+
39
+ assert_equal template.id, found_template.id
40
+ end
41
+ end
26
42
  end
@@ -16,16 +16,34 @@ class JobInvocationComposerTest < ActiveSupport::TestCase
16
16
  setup_user('create', 'hosts')
17
17
  end
18
18
 
19
+ class AnsibleInputs < RemoteExecutionProvider
20
+ class << self
21
+ def provider_input_namespace
22
+ :ansible
23
+ end
24
+
25
+ def provider_inputs
26
+ [
27
+ ForemanRemoteExecution::ProviderInput.new(name: 'tags', label: 'Tags', value: 'fooo', value_type: 'plain'),
28
+ ForemanRemoteExecution::ProviderInput.new(name: 'tags_flag', label: 'Tags Flag', value: '--tags', options: "--tags\n--skip-tags"),
29
+ ]
30
+ end
31
+ end
32
+ end
33
+ RemoteExecutionProvider.register(:AnsibleInputs, AnsibleInputs)
34
+
19
35
  let(:trying_job_template_1) { FactoryBot.create(:job_template, :job_category => 'trying_job_template_1', :name => 'trying1', :provider_type => 'SSH') }
20
36
  let(:trying_job_template_2) { FactoryBot.create(:job_template, :job_category => 'trying_job_template_2', :name => 'trying2', :provider_type => 'Mcollective') }
21
37
  let(:trying_job_template_3) { FactoryBot.create(:job_template, :job_category => 'trying_job_template_1', :name => 'trying3', :provider_type => 'SSH') }
22
38
  let(:unauthorized_job_template_1) { FactoryBot.create(:job_template, :job_category => 'trying_job_template_1', :name => 'unauth1', :provider_type => 'SSH') }
23
39
  let(:unauthorized_job_template_2) { FactoryBot.create(:job_template, :job_category => 'unauthorized_job_template_2', :name => 'unauth2', :provider_type => 'Ansible') }
24
40
 
41
+ let(:provider_inputs_job_template) { FactoryBot.create(:job_template, :job_category => 'trying_test_inputs', :name => 'trying provider inputs', :provider_type => 'AnsibleInputs') }
25
42
 
26
43
  let(:input1) { FactoryBot.create(:template_input, :template => trying_job_template_1, :input_type => 'user') }
27
44
  let(:input2) { FactoryBot.create(:template_input, :template => trying_job_template_3, :input_type => 'user') }
28
45
  let(:input3) { FactoryBot.create(:template_input, :template => trying_job_template_1, :input_type => 'user', :required => true) }
46
+ let(:input4) { FactoryBot.create(:template_input, :template => provider_inputs_job_template, :input_type => 'user') }
29
47
  let(:unauthorized_input1) { FactoryBot.create(:template_input, :template => unauthorized_job_template_1, :input_type => 'user') }
30
48
 
31
49
  let(:ansible_params) { { } }
@@ -605,7 +623,9 @@ class JobInvocationComposerTest < ActiveSupport::TestCase
605
623
  end
606
624
 
607
625
  describe '#from_api_params' do
608
- let(:composer) { JobInvocationComposer.from_api_params(params) }
626
+ let(:composer) do
627
+ JobInvocationComposer.from_api_params(params)
628
+ end
609
629
  let(:bookmark) { bookmarks(:one) }
610
630
 
611
631
  context 'with targeting from bookmark' do
@@ -659,6 +679,26 @@ class JobInvocationComposerTest < ActiveSupport::TestCase
659
679
  end
660
680
  end
661
681
 
682
+ context 'with provider inputs' do
683
+ let(:params) do
684
+ { :job_category => provider_inputs_job_template.job_category,
685
+ :job_template_id => provider_inputs_job_template.id,
686
+ :targeting_type => 'static_query',
687
+ :search_query => 'some hosts',
688
+ :inputs => { input4.name => 'some_value' },
689
+ :ansible => { 'tags' => 'bar', 'tags_flag' => '--skip-tags' } }
690
+ end
691
+
692
+ it 'detects provider inputs' do
693
+ assert composer.save!
694
+ scope = composer.job_invocation.pattern_template_invocations.first.provider_input_values
695
+ tags = scope.find_by :name => 'tags'
696
+ flags = scope.find_by :name => 'tags_flag'
697
+ assert_equal 'bar', tags.value
698
+ assert_equal '--skip-tags', flags.value
699
+ end
700
+ end
701
+
662
702
  context 'with effective user' do
663
703
  let(:params) do
664
704
  { :job_category => trying_job_template_1.job_category,
@@ -0,0 +1,57 @@
1
+ require 'test_plugin_helper'
2
+
3
+ class JobReportTemplateTest < ActiveSupport::TestCase
4
+ class FakeTask < OpenStruct
5
+ class Jail < Safemode::Jail
6
+ allow :action_continuous_output, :result, :ended_at
7
+ end
8
+ end
9
+
10
+ context 'with valid job invocation report template' do
11
+ let(:job_invocation_template) do
12
+ file_path = File.read(File.expand_path(Rails.root + "app/views/unattended/report_templates/jobs_-_invocation_report_template.erb"))
13
+ template = ReportTemplate.import_without_save("Job Invocation Report Template", file_path)
14
+ template.save!
15
+ template
16
+ end
17
+
18
+ describe 'template setting' do
19
+ it 'in settings includes only report templates with job_id input' do
20
+ FactoryBot.create(:report_template, name: 'Template 1')
21
+ job_invocation_template
22
+ templates = Setting::RemoteExecution.job_invocation_report_templates_select
23
+
24
+ assert_include templates, 'Job Invocation Report Template'
25
+ end
26
+ end
27
+
28
+ describe 'task reporting' do
29
+ let(:fake_outputs) do
30
+ [
31
+ { 'output_type' => 'stderr', 'output' => "error", 'timestamp' => Time.new(2020, 12, 1, 0, 0, 0).utc },
32
+ { 'output_type' => 'stdout', 'output' => "output", 'timestamp' => Time.new(2020, 12, 1, 0, 0, 0).utc },
33
+ { 'output_type' => 'stdebug', 'output' => "debug", 'timestamp' => Time.new(2020, 12, 1, 0, 0, 0).utc },
34
+ ]
35
+ end
36
+ let(:fake_task) { FakeTask.new(result: 'success', action_continuous_output: fake_outputs) }
37
+
38
+ it 'should render task outputs' do
39
+ job_invocation = FactoryBot.create(:job_invocation, :with_task)
40
+ JobInvocation.any_instance.expects(:sub_task_for_host).returns(fake_task)
41
+
42
+ input = job_invocation_template.template_inputs.first
43
+ composer_params = { template_id: job_invocation_template.id, input_values: { input.id.to_s => { value: job_invocation.id.to_s } } }
44
+ result = ReportComposer.new(composer_params).render
45
+
46
+ # parsing the CSV result
47
+ CSV.parse(result.strip, headers: true).each_with_index do |row, i|
48
+ row_hash = row.to_h
49
+ assert_equal 'success', row_hash['result']
50
+ assert_equal fake_outputs[i]['output_type'], row_hash['type']
51
+ assert_equal fake_outputs[i]['output'], row_hash['message']
52
+ assert_kind_of Time, Time.zone.parse(row_hash['time']), 'Parsing of time column failed'
53
+ end
54
+ end
55
+ end
56
+ end
57
+ end
@@ -1,21 +1,45 @@
1
- import React from 'react';
1
+ import React, { useState } from 'react';
2
2
  import { Wizard } from '@patternfly/react-core';
3
3
  import { translate as __ } from 'foremanReact/common/I18n';
4
4
  import history from 'foremanReact/history';
5
+ import CategoryAndTemplate from './steps/CategoryAndTemplate/';
6
+ import './JobWizard.scss';
5
7
 
6
8
  export const JobWizard = () => {
9
+ const [jobTemplate, setJobTemplate] = useState(null);
10
+ const [category, setCategory] = useState('');
7
11
  const steps = [
8
12
  {
9
13
  name: __('Category and template'),
10
- component: <p>Category and template</p>,
14
+ component: (
15
+ <CategoryAndTemplate
16
+ jobTemplate={jobTemplate}
17
+ setJobTemplate={setJobTemplate}
18
+ category={category}
19
+ setCategory={setCategory}
20
+ />
21
+ ),
22
+ },
23
+ {
24
+ name: __('Target hosts'),
25
+ component: <p>TargetHosts </p>,
26
+ canJumpTo: !!jobTemplate,
27
+ },
28
+ {
29
+ name: __('Advanced fields'),
30
+ component: <p> AdvancedFields </p>,
31
+ canJumpTo: !!jobTemplate,
32
+ },
33
+ {
34
+ name: __('Schedule'),
35
+ component: <p>Schedule</p>,
36
+ canJumpTo: !!jobTemplate,
11
37
  },
12
- { name: __('Target hosts'), component: <p>TargetHosts </p> },
13
- { name: __('Advanced fields'), component: <p> AdvancedFields </p> },
14
- { name: __('Schedule'), component: <p>Schedule</p> },
15
38
  {
16
39
  name: __('Review details'),
17
40
  component: <p>ReviewDetails</p>,
18
41
  nextButtonText: 'Run',
42
+ canJumpTo: !!jobTemplate,
19
43
  },
20
44
  ];
21
45
  const title = __('Run Job');
@@ -25,8 +49,7 @@ export const JobWizard = () => {
25
49
  navAriaLabel={`${title} steps`}
26
50
  steps={steps}
27
51
  height="70vh"
52
+ className="job-wizard"
28
53
  />
29
54
  );
30
55
  };
31
-
32
- export default JobWizard;