foreman_remote_execution 4.5.6 → 4.6.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (71) hide show
  1. checksums.yaml +4 -4
  2. data/app/controllers/job_invocations_controller.rb +1 -1
  3. data/app/controllers/ui_job_wizard_controller.rb +0 -7
  4. data/app/helpers/concerns/foreman_remote_execution/hosts_helper_extensions.rb +1 -5
  5. data/app/helpers/remote_execution_helper.rb +3 -9
  6. data/app/lib/actions/remote_execution/run_host_job.rb +1 -5
  7. data/app/lib/actions/remote_execution/run_hosts_job.rb +1 -1
  8. data/app/models/concerns/foreman_remote_execution/host_extensions.rb +0 -2
  9. data/app/models/concerns/foreman_remote_execution/orchestration/ssh.rb +70 -0
  10. data/app/models/concerns/foreman_remote_execution/smart_proxy_extensions.rb +0 -6
  11. data/app/models/host_status/execution_status.rb +3 -3
  12. data/app/models/job_invocation.rb +6 -9
  13. data/app/models/job_invocation_composer.rb +4 -4
  14. data/app/models/remote_execution_feature.rb +1 -5
  15. data/app/models/remote_execution_provider.rb +2 -3
  16. data/app/models/setting/remote_execution.rb +2 -2
  17. data/app/models/targeting.rb +1 -5
  18. data/app/views/job_invocations/index.html.erb +1 -1
  19. data/app/views/templates/ssh/module_action.erb +0 -1
  20. data/app/views/templates/ssh/power_action.erb +0 -2
  21. data/app/views/templates/ssh/puppet_run_once.erb +0 -1
  22. data/foreman_remote_execution.gemspec +0 -1
  23. data/lib/foreman_remote_execution/engine.rb +2 -0
  24. data/lib/foreman_remote_execution/version.rb +1 -1
  25. data/test/models/orchestration/ssh_test.rb +56 -0
  26. data/test/unit/job_invocation_composer_test.rb +1 -14
  27. data/test/unit/job_invocation_test.rb +1 -1
  28. data/test/unit/remote_execution_provider_test.rb +0 -12
  29. data/webpack/JobWizard/JobWizard.js +16 -59
  30. data/webpack/JobWizard/JobWizard.scss +0 -58
  31. data/webpack/JobWizard/JobWizardConstants.js +0 -18
  32. data/webpack/JobWizard/JobWizardSelectors.js +0 -9
  33. data/webpack/JobWizard/__tests__/JobWizard.test.js +13 -0
  34. data/webpack/JobWizard/__tests__/__snapshots__/JobWizard.test.js.snap +32 -0
  35. data/webpack/JobWizard/__tests__/fixtures.js +2 -112
  36. data/webpack/JobWizard/__tests__/integration.test.js +92 -16
  37. data/webpack/JobWizard/steps/AdvancedFields/AdvancedFields.js +9 -37
  38. data/webpack/JobWizard/steps/AdvancedFields/Fields.js +55 -116
  39. data/webpack/JobWizard/steps/AdvancedFields/__tests__/AdvancedFields.test.js +16 -150
  40. data/webpack/JobWizard/steps/AdvancedFields/__tests__/__snapshots__/AdvancedFields.test.js.snap +249 -0
  41. data/webpack/JobWizard/steps/CategoryAndTemplate/CategoryAndTemplate.js +2 -4
  42. data/webpack/JobWizard/steps/CategoryAndTemplate/CategoryAndTemplate.test.js +51 -123
  43. data/webpack/JobWizard/steps/CategoryAndTemplate/__snapshots__/CategoryAndTemplate.test.js.snap +113 -0
  44. data/webpack/JobWizard/steps/form/FormHelpers.js +0 -1
  45. data/webpack/JobWizard/steps/form/SelectField.js +2 -14
  46. data/webpack/JobWizard/steps/form/__tests__/GroupedSelectField.test.js +38 -0
  47. data/webpack/JobWizard/steps/form/__tests__/SelectField.test.js +23 -0
  48. data/webpack/JobWizard/steps/form/__tests__/__snapshots__/GroupedSelectField.test.js.snap +37 -0
  49. data/webpack/JobWizard/steps/form/__tests__/__snapshots__/SelectField.test.js.snap +23 -0
  50. data/webpack/__mocks__/foremanReact/components/SearchBar.js +1 -18
  51. data/webpack/react_app/components/TargetingHosts/__tests__/__snapshots__/TargetingHostsPage.test.js.snap +0 -1
  52. metadata +13 -35
  53. data/app/models/host_proxy_invocation.rb +0 -4
  54. data/db/migrate/2021051713291621250977_add_host_proxy_invocations.rb +0 -12
  55. data/webpack/JobWizard/steps/AdvancedFields/DescriptionField.js +0 -67
  56. data/webpack/JobWizard/steps/AdvancedFields/__tests__/DescriptionField.test.js +0 -23
  57. data/webpack/JobWizard/steps/HostsAndInputs/SelectedChips.js +0 -25
  58. data/webpack/JobWizard/steps/HostsAndInputs/TemplateInputs.js +0 -23
  59. data/webpack/JobWizard/steps/HostsAndInputs/__tests__/SelectedChips.test.js +0 -37
  60. data/webpack/JobWizard/steps/HostsAndInputs/__tests__/TemplateInputs.test.js +0 -50
  61. data/webpack/JobWizard/steps/HostsAndInputs/index.js +0 -66
  62. data/webpack/JobWizard/steps/Schedule/QueryType.js +0 -48
  63. data/webpack/JobWizard/steps/Schedule/RepeatOn.js +0 -61
  64. data/webpack/JobWizard/steps/Schedule/ScheduleType.js +0 -25
  65. data/webpack/JobWizard/steps/Schedule/StartEndDates.js +0 -51
  66. data/webpack/JobWizard/steps/Schedule/__tests__/StartEndDates.test.js +0 -22
  67. data/webpack/JobWizard/steps/Schedule/index.js +0 -44
  68. data/webpack/JobWizard/steps/form/Formatter.js +0 -150
  69. data/webpack/JobWizard/steps/form/NumberInput.js +0 -35
  70. data/webpack/JobWizard/steps/form/WizardTitle.js +0 -14
  71. data/webpack/JobWizard/steps/form/__tests__/Formatter.test.js.example +0 -76
@@ -1,10 +1,8 @@
1
1
  import React from 'react';
2
2
  import PropTypes from 'prop-types';
3
- import { FormGroup, TextInput, Radio } from '@patternfly/react-core';
3
+ import { FormGroup, TextInput } from '@patternfly/react-core';
4
4
  import { translate as __ } from 'foremanReact/common/I18n';
5
5
  import { helpLabel } from '../form/FormHelpers';
6
- import { formatter } from '../form/Formatter';
7
- import { NumberInput } from '../form/NumberInput';
8
6
 
9
7
  export const EffectiveUserField = ({ value, setValue }) => (
10
8
  <FormGroup
@@ -18,7 +16,6 @@ export const EffectiveUserField = ({ value, setValue }) => (
18
16
  fieldId="effective-user"
19
17
  >
20
18
  <TextInput
21
- aria-label="effective user"
22
19
  autoComplete="effective-user"
23
20
  id="effective-user"
24
21
  type="text"
@@ -29,25 +26,25 @@ export const EffectiveUserField = ({ value, setValue }) => (
29
26
  );
30
27
 
31
28
  export const TimeoutToKillField = ({ value, setValue }) => (
32
- <NumberInput
33
- formProps={{
34
- label: __('Timeout to kill'),
35
- labelIcon: helpLabel(
36
- __(
37
- 'Time in seconds from the start on the remote host after which the job should be killed.'
38
- ),
39
- 'timeout-to-kill'
29
+ <FormGroup
30
+ label={__('Timeout to kill')}
31
+ labelIcon={helpLabel(
32
+ __(
33
+ 'Time in seconds from the start on the remote host after which the job should be killed.'
40
34
  ),
41
- fieldId: 'timeout-to-kill',
42
- }}
43
- inputProps={{
44
- value,
45
- placeholder: __('For example: 1, 2, 3, 4, 5...'),
46
- autoComplete: 'timeout-to-kill',
47
- id: 'timeout-to-kill',
48
- onChange: newValue => setValue(newValue),
49
- }}
50
- />
35
+ 'timeout-to-kill'
36
+ )}
37
+ fieldId="timeout-to-kill"
38
+ >
39
+ <TextInput
40
+ type="number"
41
+ value={value}
42
+ placeholder={__('For example: 1, 2, 3, 4, 5...')}
43
+ autoComplete="timeout-to-kill"
44
+ id="timeout-to-kill"
45
+ onChange={newValue => setValue(newValue)}
46
+ />
47
+ </FormGroup>
51
48
  );
52
49
 
53
50
  export const PasswordField = ({ value, setValue }) => (
@@ -59,12 +56,11 @@ export const PasswordField = ({ value, setValue }) => (
59
56
  ),
60
57
  'password'
61
58
  )}
62
- fieldId="job-password"
59
+ fieldId="password"
63
60
  >
64
61
  <TextInput
65
- aria-label="job password"
66
- autoComplete="new-password" // to prevent firefox from autofilling the user password
67
- id="job-password"
62
+ autoComplete="password"
63
+ id="password"
68
64
  type="password"
69
65
  placeholder="*****"
70
66
  value={value}
@@ -85,7 +81,6 @@ export const KeyPassphraseField = ({ value, setValue }) => (
85
81
  fieldId="key-passphrase"
86
82
  >
87
83
  <TextInput
88
- aria-label="key passphrase"
89
84
  autoComplete="key-passphrase"
90
85
  id="key-passphrase"
91
86
  type="password"
@@ -108,7 +103,6 @@ export const EffectiveUserPasswordField = ({ value, setValue }) => (
108
103
  fieldId="effective-user-password"
109
104
  >
110
105
  <TextInput
111
- aria-label="effective userpassword"
112
106
  autoComplete="effective-user-password"
113
107
  id="effective-user-password"
114
108
  type="password"
@@ -120,89 +114,51 @@ export const EffectiveUserPasswordField = ({ value, setValue }) => (
120
114
  );
121
115
 
122
116
  export const ConcurrencyLevelField = ({ value, setValue }) => (
123
- <NumberInput
124
- formProps={{
125
- label: __('Concurrency level'),
126
- labelIcon: helpLabel(
127
- __(
128
- '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.'
129
- ),
130
- 'concurrency-level'
117
+ <FormGroup
118
+ label={__('Concurrency level')}
119
+ labelIcon={helpLabel(
120
+ __(
121
+ '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.'
131
122
  ),
132
- fieldId: 'concurrency-level',
133
- }}
134
- inputProps={{
135
- min: 1,
136
- autoComplete: 'concurrency-level',
137
- id: 'concurrency-level',
138
- placeholder: __('For example: 1, 2, 3, 4, 5...'),
139
- value,
140
- onChange: newValue => setValue(newValue),
141
- }}
142
- />
123
+ 'concurrency-level'
124
+ )}
125
+ fieldId="concurrency-level"
126
+ >
127
+ <TextInput
128
+ min={1}
129
+ type="number"
130
+ autoComplete="concurrency-level"
131
+ id="concurrency-level"
132
+ placeholder={__('For example: 1, 2, 3, 4, 5...')}
133
+ value={value}
134
+ onChange={newValue => setValue(newValue)}
135
+ />
136
+ </FormGroup>
143
137
  );
144
138
 
145
139
  export const TimeSpanLevelField = ({ value, setValue }) => (
146
- <NumberInput
147
- formProps={{
148
- label: __('Time span'),
149
- labelIcon: helpLabel(
150
- __(
151
- 'Distribute execution over N seconds. If this is set and proxy batch triggering is enabled, then tasks are triggered on the smart proxy in batches of size 1.'
152
- ),
153
- 'time-span'
154
- ),
155
- fieldId: 'time-span',
156
- }}
157
- inputProps={{
158
- min: 1,
159
- autoComplete: 'time-span',
160
- id: 'time-span',
161
- placeholder: __('For example: 1, 2, 3, 4, 5...'),
162
- value,
163
- onChange: newValue => setValue(newValue),
164
- }}
165
- />
166
- );
167
-
168
- export const ExecutionOrderingField = ({ isRandomizedOrdering, setValue }) => (
169
140
  <FormGroup
170
- label={__('Execution ordering')}
171
- fieldId="schedule-type"
141
+ label={__('Time span')}
172
142
  labelIcon={helpLabel(
173
- <div
174
- dangerouslySetInnerHTML={{
175
- __html: __(
176
- 'Execution ordering determines whether the jobs should be executed on hosts in alphabetical order or in randomized order.<br><ul><li><b>Ordered</b> - executes the jobs on hosts in alphabetical order</li><li><b>Randomized</b> - randomizes the order in which jobs are executed on hosts</li></ul>'
177
- ),
178
- }}
179
- />,
180
- 'effective-user-password'
143
+ __(
144
+ 'Distribute execution over N seconds. If this is set and proxy batch triggering is enabled, then tasks are triggered on the smart proxy in batches of size 1.'
145
+ ),
146
+ 'time-span'
181
147
  )}
182
- isInline
148
+ fieldId="time-span"
183
149
  >
184
- <Radio
185
- aria-label="execution order alphabetical"
186
- isChecked={!isRandomizedOrdering}
187
- name="execution-order"
188
- onChange={() => setValue(false)}
189
- id="execution-order-alphabetical"
190
- label={__('Alphabetical')}
191
- />
192
- <Radio
193
- aria-label="execution order randomized"
194
- isChecked={isRandomizedOrdering}
195
- name="execution-order"
196
- onChange={() => setValue(true)}
197
- id="execution-order-randomized"
198
- label={__('Randomized')}
150
+ <TextInput
151
+ min={1}
152
+ type="number"
153
+ autoComplete="time-span"
154
+ id="time-span"
155
+ placeholder={__('For example: 1, 2, 3, 4, 5...')}
156
+ value={value}
157
+ onChange={newValue => setValue(newValue)}
199
158
  />
200
159
  </FormGroup>
201
160
  );
202
161
 
203
- export const TemplateInputsFields = ({ inputs, value, setValue }) => (
204
- <>{inputs?.map(input => formatter(input, value, setValue))}</>
205
- );
206
162
  EffectiveUserField.propTypes = {
207
163
  value: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),
208
164
  setValue: PropTypes.func.isRequired,
@@ -223,20 +179,3 @@ ConcurrencyLevelField.propTypes = EffectiveUserField.propTypes;
223
179
  ConcurrencyLevelField.defaultProps = EffectiveUserField.defaultProps;
224
180
  TimeSpanLevelField.propTypes = EffectiveUserField.propTypes;
225
181
  TimeSpanLevelField.defaultProps = EffectiveUserField.defaultProps;
226
- ExecutionOrderingField.propTypes = {
227
- isRandomizedOrdering: PropTypes.bool,
228
- setValue: PropTypes.func.isRequired,
229
- };
230
- ExecutionOrderingField.defaultProps = {
231
- isRandomizedOrdering: false,
232
- };
233
-
234
- TemplateInputsFields.propTypes = {
235
- inputs: PropTypes.array.isRequired,
236
- value: PropTypes.object,
237
- setValue: PropTypes.func.isRequired,
238
- };
239
-
240
- TemplateInputsFields.defaultProps = {
241
- value: {},
242
- };
@@ -1,159 +1,25 @@
1
1
  import React from 'react';
2
2
  import { Provider } from 'react-redux';
3
+ import configureMockStore from 'redux-mock-store';
4
+ import * as patternfly from '@patternfly/react-core';
3
5
  import { mount } from '@theforeman/test';
4
- import { fireEvent, screen, render, act } from '@testing-library/react';
5
- import * as api from 'foremanReact/redux/API';
6
- import { JobWizard } from '../../../JobWizard';
7
- import * as selectors from '../../../JobWizardSelectors';
8
- import {
9
- jobTemplateResponse as jobTemplate,
10
- testSetup,
11
- mockApi,
12
- } from '../../../__tests__/fixtures';
13
- import { WIZARD_TITLES } from '../../../JobWizardConstants';
14
-
15
- const store = testSetup(selectors, api);
16
- mockApi(api);
17
-
18
- jest.spyOn(selectors, 'selectEffectiveUser');
19
-
20
- selectors.selectEffectiveUser.mockImplementation(
21
- () => jobTemplate.effective_user
22
- );
6
+ import { AdvancedFields } from '../AdvancedFields';
7
+
8
+ jest.spyOn(patternfly, 'FormGroup');
9
+ patternfly.FormGroup.mockImplementation(props => (
10
+ <div>{props.navAriaLabel}</div>
11
+ ));
12
+ const mockStore = configureMockStore([]);
13
+ const store = mockStore({
14
+ JOB_TEMPLATE: { response: { effective_user: { overridable: true } } },
15
+ });
23
16
  describe('AdvancedFields', () => {
24
- it('should save data between steps for advanced fields', async () => {
25
- const wrapper = mount(
26
- <Provider store={store}>
27
- <JobWizard advancedValues={{}} setAdvancedValues={jest.fn()} />
28
- </Provider>
29
- );
30
- // setup
31
- wrapper.find('.pf-c-button.pf-c-select__toggle-button').simulate('click');
32
- wrapper
33
- .find('.pf-c-select__menu-item')
34
- .first()
35
- .simulate('click');
36
-
37
- // test
38
- expect(wrapper.find('.pf-c-wizard__nav-link.pf-m-disabled')).toHaveLength(
39
- 0
40
- );
41
- wrapper
42
- .find('.pf-c-wizard__nav-link')
43
- .at(2)
44
- .simulate('click'); // Advanced step
45
- const effectiveUserInput = () => wrapper.find('input#effective-user');
46
- const advancedTemplateInput = () =>
47
- wrapper.find('.pf-c-form__group-control textarea');
48
- const effectiveUesrValue = 'effective user new value';
49
- const advancedTemplateInputValue = 'advanced input new value';
50
- effectiveUserInput().getDOMNode().value = effectiveUesrValue;
51
-
52
- effectiveUserInput().simulate('change');
53
- wrapper.update();
54
- advancedTemplateInput().getDOMNode().value = advancedTemplateInputValue;
55
- advancedTemplateInput().simulate('change');
56
- expect(effectiveUserInput().prop('value')).toEqual(effectiveUesrValue);
57
- expect(advancedTemplateInput().prop('value')).toEqual(
58
- advancedTemplateInputValue
59
- );
60
-
61
- wrapper
62
- .find('.pf-c-wizard__nav-link')
63
- .at(1)
64
- .simulate('click');
65
-
66
- expect(wrapper.find('.pf-c-wizard__nav-link.pf-m-current').text()).toEqual(
67
- 'Target hosts and inputs'
68
- );
69
- wrapper
70
- .find('.pf-c-wizard__nav-link')
71
- .at(2)
72
- .simulate('click'); // Advanced step
73
-
74
- expect(effectiveUserInput().prop('value')).toEqual(effectiveUesrValue);
75
- expect(advancedTemplateInput().prop('value')).toEqual(
76
- advancedTemplateInputValue
77
- );
78
- });
79
- it('fill template fields', async () => {
80
- render(
17
+ it('rendring', () => {
18
+ const component = mount(
81
19
  <Provider store={store}>
82
- <JobWizard />
20
+ <AdvancedFields advancedValues={{}} setAdvancedValues={jest.fn()} />
83
21
  </Provider>
84
22
  );
85
- await act(async () => {
86
- fireEvent.click(screen.getByText(WIZARD_TITLES.advanced));
87
- });
88
- const searchValue = 'search test';
89
- const textValue = 'I am a text';
90
- const dateValue = '08/07/2021';
91
- const textField = screen.getByLabelText('adv plain hidden', {
92
- selector: 'textarea',
93
- });
94
- const selectField = screen.getByText('option 1');
95
- const searchField = screen.getByPlaceholderText('Filter...');
96
- const dateField = screen.getByLabelText('adv date', {
97
- selector: 'input',
98
- });
99
-
100
- fireEvent.click(selectField);
101
- await act(async () => {
102
- await fireEvent.click(screen.getByText('option 2'));
103
- fireEvent.click(screen.getAllByText(WIZARD_TITLES.advanced)[0]); // to remove focus
104
- await fireEvent.change(textField, {
105
- target: { value: textValue },
106
- });
107
-
108
- await fireEvent.change(searchField, {
109
- target: { value: searchValue },
110
- });
111
- await fireEvent.change(dateField, {
112
- target: { value: dateValue },
113
- });
114
- });
115
- expect(
116
- screen.getByLabelText('adv plain hidden', {
117
- selector: 'textarea',
118
- }).value
119
- ).toBe(textValue);
120
- expect(searchField.value).toBe(searchValue);
121
- expect(dateField.value).toBe(dateValue);
122
- await act(async () => {
123
- fireEvent.click(screen.getByText(WIZARD_TITLES.categoryAndTemplate));
124
- });
125
- expect(screen.getAllByText(WIZARD_TITLES.categoryAndTemplate)).toHaveLength(
126
- 3
127
- );
128
-
129
- await act(async () => {
130
- fireEvent.click(screen.getByText('Advanced Fields'));
131
- });
132
- expect(textField.value).toBe(textValue);
133
- expect(searchField.value).toBe(searchValue);
134
- expect(dateField.value).toBe(dateValue);
135
- expect(screen.queryAllByText('option 1')).toHaveLength(0);
136
- expect(screen.queryAllByText('option 2')).toHaveLength(1);
137
- });
138
- it('fill defaults into fields', async () => {
139
- render(
140
- <Provider store={store}>
141
- <JobWizard />
142
- </Provider>
143
- );
144
- await act(async () => {
145
- fireEvent.click(screen.getByText('Advanced Fields'));
146
- });
147
-
148
- expect(
149
- screen.getByLabelText('effective user', {
150
- selector: 'input',
151
- }).value
152
- ).toBe('default effective user');
153
- expect(
154
- screen.getByLabelText('timeout to kill', {
155
- selector: 'input',
156
- }).value
157
- ).toBe('2');
23
+ expect(component).toMatchSnapshot();
158
24
  });
159
25
  });
@@ -0,0 +1,249 @@
1
+ // Jest Snapshot v1, https://goo.gl/fbAQLP
2
+
3
+ exports[`AdvancedFields rendring 1`] = `
4
+ <Provider
5
+ store={
6
+ Object {
7
+ "clearActions": [Function],
8
+ "dispatch": [Function],
9
+ "getActions": [Function],
10
+ "getState": [Function],
11
+ "replaceReducer": [Function],
12
+ "subscribe": [Function],
13
+ }
14
+ }
15
+ >
16
+ <AdvancedFields
17
+ advancedValues={Object {}}
18
+ setAdvancedValues={[MockFunction]}
19
+ >
20
+ <Title
21
+ className="advanced-fields-title"
22
+ headingLevel="h2"
23
+ >
24
+ <h2
25
+ className="pf-c-title pf-m-xl advanced-fields-title"
26
+ >
27
+ Advanced Fields
28
+ </h2>
29
+ </Title>
30
+ <Form>
31
+ <form
32
+ className="pf-c-form"
33
+ noValidate={true}
34
+ >
35
+ <EffectiveUserField
36
+ setValue={[Function]}
37
+ value=""
38
+ >
39
+ <mockConstructor
40
+ fieldId="effective-user"
41
+ label="Effective user"
42
+ labelIcon={
43
+ <Popover
44
+ aria-label="help-text"
45
+ bodyContent="A user to be used for executing the script. If it differs from the SSH user, su or sudo is used to switch the accounts."
46
+ id="effective-user-help"
47
+ >
48
+ <button
49
+ aria-label="open-help-tooltip-button"
50
+ className="pf-c-form__group-label-help"
51
+ onClick={[Function]}
52
+ >
53
+ <HelpIcon
54
+ color="currentColor"
55
+ noVerticalAlign={true}
56
+ size="sm"
57
+ />
58
+ </button>
59
+ </Popover>
60
+ }
61
+ >
62
+ <div />
63
+ </mockConstructor>
64
+ </EffectiveUserField>
65
+ <TimeoutToKillField
66
+ setValue={[Function]}
67
+ value=""
68
+ >
69
+ <mockConstructor
70
+ fieldId="timeout-to-kill"
71
+ label="Timeout to kill"
72
+ labelIcon={
73
+ <Popover
74
+ aria-label="help-text"
75
+ bodyContent="Time in seconds from the start on the remote host after which the job should be killed."
76
+ id="timeout-to-kill-help"
77
+ >
78
+ <button
79
+ aria-label="open-help-tooltip-button"
80
+ className="pf-c-form__group-label-help"
81
+ onClick={[Function]}
82
+ >
83
+ <HelpIcon
84
+ color="currentColor"
85
+ noVerticalAlign={true}
86
+ size="sm"
87
+ />
88
+ </button>
89
+ </Popover>
90
+ }
91
+ >
92
+ <div />
93
+ </mockConstructor>
94
+ </TimeoutToKillField>
95
+ <PasswordField
96
+ setValue={[Function]}
97
+ value=""
98
+ >
99
+ <mockConstructor
100
+ fieldId="password"
101
+ label="Password"
102
+ labelIcon={
103
+ <Popover
104
+ aria-label="help-text"
105
+ bodyContent="Password is stored encrypted in DB until the job finishes. For future or recurring executions, it is removed after the last execution."
106
+ id="password-help"
107
+ >
108
+ <button
109
+ aria-label="open-help-tooltip-button"
110
+ className="pf-c-form__group-label-help"
111
+ onClick={[Function]}
112
+ >
113
+ <HelpIcon
114
+ color="currentColor"
115
+ noVerticalAlign={true}
116
+ size="sm"
117
+ />
118
+ </button>
119
+ </Popover>
120
+ }
121
+ >
122
+ <div />
123
+ </mockConstructor>
124
+ </PasswordField>
125
+ <KeyPassphraseField
126
+ setValue={[Function]}
127
+ value=""
128
+ >
129
+ <mockConstructor
130
+ fieldId="key-passphrase"
131
+ label="Private key passphrase"
132
+ labelIcon={
133
+ <Popover
134
+ aria-label="help-text"
135
+ bodyContent="Key passphrase is only applicable for SSH provider. Other providers ignore this field. Passphrase is stored encrypted in DB until the job finishes. For future or recurring executions, it is removed after the last execution."
136
+ id="key-passphrase-help"
137
+ >
138
+ <button
139
+ aria-label="open-help-tooltip-button"
140
+ className="pf-c-form__group-label-help"
141
+ onClick={[Function]}
142
+ >
143
+ <HelpIcon
144
+ color="currentColor"
145
+ noVerticalAlign={true}
146
+ size="sm"
147
+ />
148
+ </button>
149
+ </Popover>
150
+ }
151
+ >
152
+ <div />
153
+ </mockConstructor>
154
+ </KeyPassphraseField>
155
+ <EffectiveUserPasswordField
156
+ setValue={[Function]}
157
+ value=""
158
+ >
159
+ <mockConstructor
160
+ fieldId="effective-user-password"
161
+ label="Effective user password"
162
+ labelIcon={
163
+ <Popover
164
+ aria-label="help-text"
165
+ bodyContent="Effective user password is only applicable for SSH provider. Other providers ignore this field. Password is stored encrypted in DB until the job finishes. For future or recurring executions, it is removed after the last execution."
166
+ id="effective-user-password-help"
167
+ >
168
+ <button
169
+ aria-label="open-help-tooltip-button"
170
+ className="pf-c-form__group-label-help"
171
+ onClick={[Function]}
172
+ >
173
+ <HelpIcon
174
+ color="currentColor"
175
+ noVerticalAlign={true}
176
+ size="sm"
177
+ />
178
+ </button>
179
+ </Popover>
180
+ }
181
+ >
182
+ <div />
183
+ </mockConstructor>
184
+ </EffectiveUserPasswordField>
185
+ <ConcurrencyLevelField
186
+ setValue={[Function]}
187
+ value=""
188
+ >
189
+ <mockConstructor
190
+ fieldId="concurrency-level"
191
+ label="Concurrency level"
192
+ labelIcon={
193
+ <Popover
194
+ aria-label="help-text"
195
+ bodyContent="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."
196
+ id="concurrency-level-help"
197
+ >
198
+ <button
199
+ aria-label="open-help-tooltip-button"
200
+ className="pf-c-form__group-label-help"
201
+ onClick={[Function]}
202
+ >
203
+ <HelpIcon
204
+ color="currentColor"
205
+ noVerticalAlign={true}
206
+ size="sm"
207
+ />
208
+ </button>
209
+ </Popover>
210
+ }
211
+ >
212
+ <div />
213
+ </mockConstructor>
214
+ </ConcurrencyLevelField>
215
+ <TimeSpanLevelField
216
+ setValue={[Function]}
217
+ value=""
218
+ >
219
+ <mockConstructor
220
+ fieldId="time-span"
221
+ label="Time span"
222
+ labelIcon={
223
+ <Popover
224
+ aria-label="help-text"
225
+ bodyContent="Distribute execution over N seconds. If this is set and proxy batch triggering is enabled, then tasks are triggered on the smart proxy in batches of size 1."
226
+ id="time-span-help"
227
+ >
228
+ <button
229
+ aria-label="open-help-tooltip-button"
230
+ className="pf-c-form__group-label-help"
231
+ onClick={[Function]}
232
+ >
233
+ <HelpIcon
234
+ color="currentColor"
235
+ noVerticalAlign={true}
236
+ size="sm"
237
+ />
238
+ </button>
239
+ </Popover>
240
+ }
241
+ >
242
+ <div />
243
+ </mockConstructor>
244
+ </TimeSpanLevelField>
245
+ </form>
246
+ </Form>
247
+ </AdvancedFields>
248
+ </Provider>
249
+ `;
@@ -1,11 +1,9 @@
1
1
  import React from 'react';
2
2
  import PropTypes from 'prop-types';
3
- import { Text, TextVariants, Form, Alert } from '@patternfly/react-core';
3
+ import { Title, Text, TextVariants, Form, Alert } from '@patternfly/react-core';
4
4
  import { translate as __ } from 'foremanReact/common/I18n';
5
5
  import { SelectField } from '../form/SelectField';
6
6
  import { GroupedSelectField } from '../form/GroupedSelectField';
7
- import { WizardTitle } from '../form/WizardTitle';
8
- import { WIZARD_TITLES } from '../../JobWizardConstants';
9
7
 
10
8
  export const CategoryAndTemplate = ({
11
9
  jobCategories,
@@ -42,7 +40,7 @@ export const CategoryAndTemplate = ({
42
40
  const isError = !!(categoryError || allTemplatesError || templateError);
43
41
  return (
44
42
  <>
45
- <WizardTitle title={WIZARD_TITLES.categoryAndTemplate} />
43
+ <Title headingLevel="h2">{__('Category and Template')}</Title>
46
44
  <Text component={TextVariants.p}>{__('All fields are required.')}</Text>
47
45
  <Form>
48
46
  <SelectField