foreman_remote_execution 4.4.0 → 4.5.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/app/controllers/api/v2/job_invocations_controller.rb +13 -24
- data/app/controllers/job_templates_controller.rb +4 -4
- data/app/controllers/ui_job_wizard_controller.rb +12 -0
- data/app/helpers/job_invocations_helper.rb +2 -2
- data/app/helpers/remote_execution_helper.rb +8 -8
- data/app/lib/actions/remote_execution/run_host_job.rb +31 -5
- data/app/models/concerns/foreman_remote_execution/host_extensions.rb +5 -5
- data/app/models/host_status/execution_status.rb +5 -5
- data/app/models/job_invocation.rb +23 -7
- data/app/models/job_invocation_composer.rb +59 -17
- data/app/models/ssh_execution_provider.rb +4 -4
- data/app/overrides/execution_interface.rb +8 -8
- data/app/overrides/subnet_proxies.rb +6 -6
- data/config/routes.rb +1 -0
- data/db/migrate/20180110104432_rename_template_invocation_permission.rb +1 -1
- data/db/migrate/20190111153330_remove_remote_execution_without_proxy_setting.rb +4 -4
- data/extra/cockpit/foreman-cockpit-session +6 -6
- data/lib/foreman_remote_execution/engine.rb +11 -6
- data/lib/foreman_remote_execution/version.rb +1 -1
- data/package.json +2 -1
- data/test/functional/api/v2/job_invocations_controller_test.rb +14 -1
- data/test/unit/job_invocation_composer_test.rb +45 -1
- data/webpack/JobWizard/JobWizard.js +59 -18
- data/webpack/JobWizard/JobWizard.scss +3 -1
- data/webpack/JobWizard/JobWizardConstants.js +1 -0
- data/webpack/JobWizard/JobWizardSelectors.js +18 -1
- data/webpack/JobWizard/__tests__/JobWizard.test.js +4 -11
- data/webpack/JobWizard/__tests__/__snapshots__/JobWizard.test.js.snap +0 -51
- data/webpack/JobWizard/__tests__/__snapshots__/integration.test.js.snap +43 -0
- data/webpack/JobWizard/__tests__/fixtures.js +26 -0
- data/webpack/JobWizard/__tests__/integration.test.js +156 -0
- data/webpack/JobWizard/steps/AdvancedFields/AdvancedFields.js +93 -0
- data/webpack/JobWizard/steps/AdvancedFields/Fields.js +181 -0
- data/webpack/JobWizard/steps/AdvancedFields/__tests__/AdvancedFields.test.js +25 -0
- data/webpack/JobWizard/steps/AdvancedFields/__tests__/__snapshots__/AdvancedFields.test.js.snap +249 -0
- data/webpack/JobWizard/steps/CategoryAndTemplate/CategoryAndTemplate.js +34 -2
- data/webpack/JobWizard/steps/CategoryAndTemplate/CategoryAndTemplate.test.js +10 -3
- data/webpack/JobWizard/steps/CategoryAndTemplate/__snapshots__/CategoryAndTemplate.test.js.snap +50 -1
- data/webpack/JobWizard/steps/CategoryAndTemplate/index.js +9 -1
- data/webpack/JobWizard/steps/form/FormHelpers.js +19 -0
- data/webpack/JobWizard/steps/form/GroupedSelectField.js +3 -0
- data/webpack/JobWizard/steps/form/SelectField.js +10 -1
- data/webpack/JobWizard/steps/form/__tests__/__snapshots__/GroupedSelectField.test.js.snap +1 -0
- data/webpack/JobWizard/steps/form/__tests__/__snapshots__/SelectField.test.js.snap +1 -0
- data/webpack/__mocks__/foremanReact/redux/API/APISelectors.js +21 -2
- data/webpack/global_index.js +5 -3
- data/webpack/index.js +3 -0
- data/webpack/react_app/components/RecentJobsCard/RecentJobsCard.js +1 -5
- data/webpack/react_app/components/TargetingHosts/__tests__/TargetingHostsSelectors.test.js +8 -3
- data/webpack/react_app/components/TargetingHosts/__tests__/__snapshots__/TargetingHostsSelectors.test.js.snap +7 -2
- data/webpack/react_app/extend/{fills.js → fillRecentJobsCard.js} +7 -6
- data/webpack/react_app/extend/fillregistrationAdvanced.js +11 -0
- data/webpack/react_app/extend/reducers.js +2 -1
- metadata +12 -4
- data/webpack/fills_index.js +0 -11
@@ -2,10 +2,10 @@ class SSHExecutionProvider < RemoteExecutionProvider
|
|
2
2
|
class << self
|
3
3
|
def proxy_command_options(template_invocation, host)
|
4
4
|
super.merge(:ssh_user => ssh_user(host),
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
5
|
+
:effective_user => effective_user(template_invocation),
|
6
|
+
:effective_user_method => effective_user_method(host),
|
7
|
+
:cleanup_working_dirs => cleanup_working_dirs?(host),
|
8
|
+
:ssh_port => ssh_port(host))
|
9
9
|
end
|
10
10
|
|
11
11
|
def humanized_name
|
@@ -1,9 +1,9 @@
|
|
1
|
-
Deface::Override.new(:virtual_path
|
2
|
-
|
3
|
-
|
4
|
-
|
1
|
+
Deface::Override.new(:virtual_path => 'hosts/_form',
|
2
|
+
:name => 'add_execution_interface_js',
|
3
|
+
:insert_before => 'div#primary',
|
4
|
+
:text => '<%= javascript "foreman_remote_execution/execution_interface" %>')
|
5
5
|
|
6
|
-
Deface::Override.new(:virtual_path
|
7
|
-
|
8
|
-
|
9
|
-
|
6
|
+
Deface::Override.new(:virtual_path => 'nic/_base_form',
|
7
|
+
:name => 'add_execution_interface',
|
8
|
+
:insert_after => 'erb[loud]:contains("interface_provision")',
|
9
|
+
:partial => 'overrides/nics/execution_interface')
|
@@ -1,9 +1,9 @@
|
|
1
1
|
Deface::Override.new(:virtual_path => 'subnets/_form',
|
2
|
-
|
3
|
-
|
4
|
-
|
2
|
+
:name => 'add_remote_execution_proxies_tab',
|
3
|
+
:insert_after => 'li.active',
|
4
|
+
:partial => 'overrides/subnets/rex_tab')
|
5
5
|
|
6
6
|
Deface::Override.new(:virtual_path => 'subnets/_form',
|
7
|
-
|
8
|
-
|
9
|
-
|
7
|
+
:name => 'add_remote_execution_proxies_tab_pane',
|
8
|
+
:insert_after => 'div#proxies',
|
9
|
+
:partial => 'overrides/subnets/rex_tab_pane')
|
data/config/routes.rb
CHANGED
@@ -44,6 +44,7 @@ Rails.application.routes.draw do
|
|
44
44
|
end
|
45
45
|
get 'cockpit/redirect', to: 'cockpit#redirect'
|
46
46
|
get 'ui_job_wizard/categories', to: 'ui_job_wizard#categories'
|
47
|
+
get 'ui_job_wizard/template/:id', to: 'ui_job_wizard#template'
|
47
48
|
|
48
49
|
match '/experimental/job_wizard', to: 'react#index', :via => [:get]
|
49
50
|
|
@@ -16,7 +16,7 @@ class RenameTemplateInvocationPermission < ActiveRecord::Migration[4.2]
|
|
16
16
|
return if old_permission.nil?
|
17
17
|
|
18
18
|
new_permission = Permission.find_or_create_by(:name => new,
|
19
|
-
|
19
|
+
:resource_type => 'TemplateInvocation')
|
20
20
|
old_permission.filterings.each do |filtering|
|
21
21
|
filtering.permission_id = new_permission.id
|
22
22
|
filtering.save!
|
@@ -5,9 +5,9 @@ class RemoveRemoteExecutionWithoutProxySetting < ActiveRecord::Migration[5.2]
|
|
5
5
|
|
6
6
|
def down
|
7
7
|
Setting.create!(:name => 'remote_execution_without_proxy',
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
8
|
+
:description => N_('When enabled, the remote execution will try to run '\
|
9
|
+
'the commands directly, when no proxy with remote execution '\
|
10
|
+
'feature is configured for the host.'),
|
11
|
+
:default => false, :full_name => N_('Fallback Without Proxy'))
|
12
12
|
end
|
13
13
|
end
|
@@ -56,13 +56,13 @@ end
|
|
56
56
|
|
57
57
|
def send_auth_challenge(challenge)
|
58
58
|
send_control({ "command" => "authorize",
|
59
|
-
|
60
|
-
|
59
|
+
"cookie" => "1234", # must be present, but value doesn't matter
|
60
|
+
"challenge" => challenge})
|
61
61
|
end
|
62
62
|
|
63
63
|
def send_auth_response(response)
|
64
64
|
send_control({ "command" => "authorize",
|
65
|
-
|
65
|
+
"response" => response})
|
66
66
|
end
|
67
67
|
|
68
68
|
def read_auth_reply
|
@@ -76,9 +76,9 @@ end
|
|
76
76
|
def exit_with_problem(problem, message, auth_methods)
|
77
77
|
LOG.error("#{problem} - #{message}")
|
78
78
|
send_control({ "command" => "init",
|
79
|
-
|
80
|
-
|
81
|
-
|
79
|
+
"problem" => problem,
|
80
|
+
"message" => message,
|
81
|
+
"auth-method-results" => auth_methods})
|
82
82
|
exit 1
|
83
83
|
end
|
84
84
|
|
@@ -51,14 +51,13 @@ module ForemanRemoteExecution
|
|
51
51
|
|
52
52
|
initializer 'foreman_remote_execution.register_plugin', before: :finisher_hook do |_app|
|
53
53
|
Foreman::Plugin.register :foreman_remote_execution do
|
54
|
-
register_global_js_file 'global'
|
55
54
|
requires_foreman '>= 2.2'
|
55
|
+
register_global_js_file 'global'
|
56
56
|
|
57
57
|
apipie_documented_controllers ["#{ForemanRemoteExecution::Engine.root}/app/controllers/api/v2/*.rb"]
|
58
58
|
ApipieDSL.configuration.dsl_classes_matchers += [
|
59
59
|
"#{ForemanRemoteExecution::Engine.root}/app/lib/foreman_remote_execution/renderer/**/*.rb",
|
60
60
|
]
|
61
|
-
register_global_js_file 'global'
|
62
61
|
automatic_assets(false)
|
63
62
|
precompile_assets(*assets_to_precompile)
|
64
63
|
|
@@ -68,7 +67,7 @@ module ForemanRemoteExecution
|
|
68
67
|
:'api/v2/job_templates' => [:index, :show, :revision, :export],
|
69
68
|
:'api/v2/template_inputs' => [:index, :show],
|
70
69
|
:'api/v2/foreign_input_sets' => [:index, :show],
|
71
|
-
:ui_job_wizard => [:categories]}, :resource_type => 'JobTemplate'
|
70
|
+
:ui_job_wizard => [:categories, :template]}, :resource_type => 'JobTemplate'
|
72
71
|
permission :create_job_templates, { :job_templates => [:new, :create, :clone_template, :import],
|
73
72
|
:'api/v2/job_templates' => [:create, :clone, :import] }, :resource_type => 'JobTemplate'
|
74
73
|
permission :edit_job_templates, { :job_templates => [:edit, :update],
|
@@ -141,7 +140,7 @@ module ForemanRemoteExecution
|
|
141
140
|
url_hash: { controller: 'job_wizard', action: :index },
|
142
141
|
caption: N_('Job wizard'),
|
143
142
|
parent: :lab_features_menu,
|
144
|
-
url: 'experimental/job_wizard',
|
143
|
+
url: '/experimental/job_wizard',
|
145
144
|
after: :host_wizard
|
146
145
|
|
147
146
|
register_custom_status HostStatus::ExecutionStatus
|
@@ -163,9 +162,15 @@ module ForemanRemoteExecution
|
|
163
162
|
|
164
163
|
# Extend Registration module
|
165
164
|
extend_allowed_registration_vars :remote_execution_interface
|
166
|
-
register_global_js_file 'fills'
|
167
165
|
ForemanTasks.dynflow.eager_load_actions!
|
168
|
-
extend_observable_events(
|
166
|
+
extend_observable_events(
|
167
|
+
::Dynflow::Action.descendants.select do |klass|
|
168
|
+
klass <= ::Actions::ObservableAction
|
169
|
+
end.map(&:namespaced_event_names) +
|
170
|
+
RemoteExecutionFeature.all.pluck(:label).map do |label|
|
171
|
+
::Actions::RemoteExecution::RunHostJob.feature_job_event_name(label)
|
172
|
+
end
|
173
|
+
)
|
169
174
|
end
|
170
175
|
end
|
171
176
|
|
data/package.json
CHANGED
@@ -29,7 +29,8 @@
|
|
29
29
|
"babel-eslint": "^10.0.0",
|
30
30
|
"eslint": "^6.8.0",
|
31
31
|
"prettier": "^1.19.1",
|
32
|
-
"@patternfly/react-catalog-view-extension": "^4.8.126"
|
32
|
+
"@patternfly/react-catalog-view-extension": "^4.8.126",
|
33
|
+
"redux-mock-store": "^1.2.2"
|
33
34
|
},
|
34
35
|
"peerDependencies": {
|
35
36
|
"@theforeman/vendor": "^8.3.0"
|
@@ -114,11 +114,24 @@ module Api
|
|
114
114
|
assert_response :success
|
115
115
|
end
|
116
116
|
|
117
|
-
test 'search_query' do
|
117
|
+
test 'host ids as search_query' do
|
118
118
|
@attrs[:host_ids] = 'name = testfqdn'
|
119
119
|
post :create, params: { job_invocation: @attrs }
|
120
120
|
assert_response :success
|
121
121
|
end
|
122
|
+
|
123
|
+
test 'with search_query param' do
|
124
|
+
@attrs[:targeting_type] = 'static_query'
|
125
|
+
@attrs[:search_query] = 'name = testfqdn'
|
126
|
+
post :create, params: { job_invocation: @attrs }
|
127
|
+
assert_response :success
|
128
|
+
end
|
129
|
+
|
130
|
+
test 'with job_template_id param' do
|
131
|
+
@attrs[:job_template_id] = 12_345
|
132
|
+
post :create, params: { job_invocation: @attrs }
|
133
|
+
assert_response :error
|
134
|
+
end
|
122
135
|
end
|
123
136
|
end
|
124
137
|
|
@@ -622,7 +622,7 @@ class JobInvocationComposerTest < ActiveSupport::TestCase
|
|
622
622
|
end
|
623
623
|
end
|
624
624
|
|
625
|
-
describe '
|
625
|
+
describe '.from_api_params' do
|
626
626
|
let(:composer) do
|
627
627
|
JobInvocationComposer.from_api_params(params)
|
628
628
|
end
|
@@ -754,12 +754,23 @@ class JobInvocationComposerTest < ActiveSupport::TestCase
|
|
754
754
|
assert composer.save!
|
755
755
|
_(composer.job_invocation.remote_execution_feature).must_equal feature
|
756
756
|
end
|
757
|
+
|
758
|
+
it 'sets the remote execution_feature id based on `feature` param' do
|
759
|
+
params[:remote_execution_feature_id] = nil
|
760
|
+
params[:feature] = feature.label
|
761
|
+
params[:job_template_id] = trying_job_template_1.id
|
762
|
+
refute_equal feature.job_template, trying_job_template_1
|
763
|
+
|
764
|
+
assert composer.save!
|
765
|
+
_(composer.job_invocation.remote_execution_feature).must_equal feature
|
766
|
+
end
|
757
767
|
end
|
758
768
|
|
759
769
|
context 'with invalid targeting' do
|
760
770
|
let(:params) do
|
761
771
|
{ :job_category => trying_job_template_1.job_category,
|
762
772
|
:job_template_id => trying_job_template_1.id,
|
773
|
+
:targeting_type => 'fake',
|
763
774
|
:search_query => 'some hosts',
|
764
775
|
:inputs => {input1.name => 'some_value'}}
|
765
776
|
end
|
@@ -865,6 +876,39 @@ class JobInvocationComposerTest < ActiveSupport::TestCase
|
|
865
876
|
end
|
866
877
|
end
|
867
878
|
|
879
|
+
describe '.for_feature' do
|
880
|
+
let(:feature) { FactoryBot.create(:remote_execution_feature, job_template: trying_job_template_1) }
|
881
|
+
let(:host) { FactoryBot.create(:host) }
|
882
|
+
let(:bookmark) { Bookmark.create!(:query => 'b', :name => 'bookmark', :public => true, :controller => 'hosts') }
|
883
|
+
|
884
|
+
context 'specifying hosts' do
|
885
|
+
it 'takes a bookmarked search' do
|
886
|
+
composer = JobInvocationComposer.for_feature(feature.label, bookmark, {})
|
887
|
+
assert_equal bookmark.id, composer.params['targeting']['bookmark_id']
|
888
|
+
end
|
889
|
+
|
890
|
+
it 'takes an array of host ids' do
|
891
|
+
composer = JobInvocationComposer.for_feature(feature.label, [host.id], {})
|
892
|
+
assert_match(/#{host.name}/, composer.params['targeting']['search_query'])
|
893
|
+
end
|
894
|
+
|
895
|
+
it 'takes a single host object' do
|
896
|
+
composer = JobInvocationComposer.for_feature(feature.label, host, {})
|
897
|
+
assert_match(/#{host.name}/, composer.params['targeting']['search_query'])
|
898
|
+
end
|
899
|
+
|
900
|
+
it 'takes an array of host FQDNs' do
|
901
|
+
composer = JobInvocationComposer.for_feature(feature.label, [host.fqdn], {})
|
902
|
+
assert_match(/#{host.name}/, composer.params['targeting']['search_query'])
|
903
|
+
end
|
904
|
+
|
905
|
+
it 'takes a search query string' do
|
906
|
+
composer = JobInvocationComposer.for_feature(feature.label, 'host.example.com', {})
|
907
|
+
assert_equal 'host.example.com', composer.search_query
|
908
|
+
end
|
909
|
+
end
|
910
|
+
end
|
911
|
+
|
868
912
|
describe '#resolve_job_category and #resolve job_templates' do
|
869
913
|
let(:setting_template) { as_admin { FactoryBot.create(:job_template, :name => 'trying setting', :job_category => 'fluff') } }
|
870
914
|
let(:other_template) { as_admin { FactoryBot.create(:job_template, :name => 'trying something', :job_category => 'fluff') } }
|
@@ -1,55 +1,96 @@
|
|
1
|
-
import React, { useState } from 'react';
|
1
|
+
import React, { useState, useEffect, useCallback } from 'react';
|
2
|
+
import { useDispatch, useSelector } from 'react-redux';
|
2
3
|
import { Wizard } from '@patternfly/react-core';
|
4
|
+
import { get } from 'foremanReact/redux/API';
|
3
5
|
import { translate as __ } from 'foremanReact/common/I18n';
|
4
6
|
import history from 'foremanReact/history';
|
5
7
|
import CategoryAndTemplate from './steps/CategoryAndTemplate/';
|
8
|
+
import { AdvancedFields } from './steps/AdvancedFields/AdvancedFields';
|
9
|
+
import { JOB_TEMPLATE } from './JobWizardConstants';
|
10
|
+
import { selectTemplateError } from './JobWizardSelectors';
|
6
11
|
import './JobWizard.scss';
|
7
12
|
|
8
13
|
export const JobWizard = () => {
|
9
|
-
const [
|
14
|
+
const [jobTemplateID, setJobTemplateID] = useState(null);
|
10
15
|
const [category, setCategory] = useState('');
|
16
|
+
const [advancedValues, setAdvancedValues] = useState({});
|
17
|
+
const dispatch = useDispatch();
|
18
|
+
|
19
|
+
const setDefaults = useCallback(response => {
|
20
|
+
const responseJob = response.data;
|
21
|
+
setAdvancedValues({
|
22
|
+
effectiveUserValue: responseJob.effective_user?.value || '',
|
23
|
+
timeoutToKill: responseJob.job_template.execution_timeout_interval || '',
|
24
|
+
});
|
25
|
+
}, []);
|
26
|
+
useEffect(() => {
|
27
|
+
if (jobTemplateID) {
|
28
|
+
dispatch(
|
29
|
+
get({
|
30
|
+
key: JOB_TEMPLATE,
|
31
|
+
url: `/ui_job_wizard/template/${jobTemplateID}`,
|
32
|
+
handleSuccess: setDefaults,
|
33
|
+
})
|
34
|
+
);
|
35
|
+
}
|
36
|
+
}, [jobTemplateID, setDefaults, dispatch]);
|
37
|
+
|
38
|
+
const templateError = !!useSelector(selectTemplateError);
|
39
|
+
const isTemplate = !templateError && !!jobTemplateID;
|
11
40
|
const steps = [
|
12
41
|
{
|
13
|
-
name: __('Category and
|
42
|
+
name: __('Category and Template'),
|
14
43
|
component: (
|
15
44
|
<CategoryAndTemplate
|
16
|
-
jobTemplate={
|
17
|
-
setJobTemplate={
|
45
|
+
jobTemplate={jobTemplateID}
|
46
|
+
setJobTemplate={setJobTemplateID}
|
18
47
|
category={category}
|
19
48
|
setCategory={setCategory}
|
20
49
|
/>
|
21
50
|
),
|
22
51
|
},
|
23
52
|
{
|
24
|
-
name: __('Target
|
25
|
-
component: <p>
|
26
|
-
canJumpTo:
|
53
|
+
name: __('Target Hosts'),
|
54
|
+
component: <p>Target Hosts</p>,
|
55
|
+
canJumpTo: isTemplate,
|
27
56
|
},
|
28
57
|
{
|
29
|
-
name: __('Advanced
|
30
|
-
component:
|
31
|
-
|
58
|
+
name: __('Advanced Fields'),
|
59
|
+
component: (
|
60
|
+
<AdvancedFields
|
61
|
+
advancedValues={advancedValues}
|
62
|
+
setAdvancedValues={newValues => {
|
63
|
+
setAdvancedValues(currentAdvancedValues => ({
|
64
|
+
...currentAdvancedValues,
|
65
|
+
...newValues,
|
66
|
+
}));
|
67
|
+
}}
|
68
|
+
jobTemplateID={jobTemplateID}
|
69
|
+
/>
|
70
|
+
),
|
71
|
+
canJumpTo: isTemplate,
|
32
72
|
},
|
33
73
|
{
|
34
74
|
name: __('Schedule'),
|
35
75
|
component: <p>Schedule</p>,
|
36
|
-
canJumpTo:
|
76
|
+
canJumpTo: isTemplate,
|
37
77
|
},
|
38
78
|
{
|
39
|
-
name: __('Review
|
40
|
-
component: <p>
|
79
|
+
name: __('Review Details'),
|
80
|
+
component: <p>Review Details</p>,
|
41
81
|
nextButtonText: 'Run',
|
42
|
-
canJumpTo:
|
82
|
+
canJumpTo: isTemplate,
|
43
83
|
},
|
44
84
|
];
|
45
|
-
const title = __('Run Job');
|
46
85
|
return (
|
47
86
|
<Wizard
|
48
87
|
onClose={() => history.goBack()}
|
49
|
-
navAriaLabel=
|
88
|
+
navAriaLabel="Run Job steps"
|
50
89
|
steps={steps}
|
51
|
-
height="
|
90
|
+
height="100%"
|
52
91
|
className="job-wizard"
|
53
92
|
/>
|
54
93
|
);
|
55
94
|
};
|
95
|
+
|
96
|
+
export default JobWizard;
|
@@ -1,6 +1,5 @@
|
|
1
1
|
.job-wizard {
|
2
2
|
.pf-c-wizard__main {
|
3
|
-
overflow: visible;
|
4
3
|
z-index: calc(
|
5
4
|
var(--pf-c-wizard__footer--ZIndex) + 1
|
6
5
|
); // So the select box can be shown above the wizard footer
|
@@ -8,5 +7,8 @@
|
|
8
7
|
|
9
8
|
.pf-c-wizard__main-body {
|
10
9
|
max-width: 500px;
|
10
|
+
.advanced-fields-title {
|
11
|
+
margin-bottom: 10px;
|
12
|
+
}
|
11
13
|
}
|
12
14
|
}
|
@@ -1,9 +1,14 @@
|
|
1
1
|
import {
|
2
2
|
selectAPIResponse,
|
3
3
|
selectAPIStatus,
|
4
|
+
selectAPIErrorMessage,
|
4
5
|
} from 'foremanReact/redux/API/APISelectors';
|
5
6
|
|
6
|
-
import {
|
7
|
+
import {
|
8
|
+
JOB_TEMPLATES,
|
9
|
+
JOB_CATEGORIES,
|
10
|
+
JOB_TEMPLATE,
|
11
|
+
} from './JobWizardConstants';
|
7
12
|
|
8
13
|
export const selectJobTemplatesStatus = state =>
|
9
14
|
selectAPIStatus(state, JOB_TEMPLATES);
|
@@ -19,3 +24,15 @@ export const selectJobCategories = state =>
|
|
19
24
|
|
20
25
|
export const selectJobCategoriesStatus = state =>
|
21
26
|
selectAPIStatus(state, JOB_CATEGORIES);
|
27
|
+
|
28
|
+
export const selectCategoryError = state =>
|
29
|
+
selectAPIErrorMessage(state, JOB_CATEGORIES);
|
30
|
+
|
31
|
+
export const selectAllTemplatesError = state =>
|
32
|
+
selectAPIErrorMessage(state, JOB_TEMPLATES);
|
33
|
+
|
34
|
+
export const selectTemplateError = state =>
|
35
|
+
selectAPIErrorMessage(state, JOB_TEMPLATE);
|
36
|
+
|
37
|
+
export const selectJobTemplate = state =>
|
38
|
+
selectAPIResponse(state, JOB_TEMPLATE);
|