foreman_remote_execution 4.5.6 → 4.6.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.
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,150 +0,0 @@
1
- import React, { useEffect } from 'react';
2
- import { useSelector } from 'react-redux';
3
- import { FormGroup, TextInput, TextArea } from '@patternfly/react-core';
4
- import PropTypes from 'prop-types';
5
- import SearchBar from 'foremanReact/components/SearchBar';
6
- import { helpLabel } from './FormHelpers';
7
- import { SelectField } from './SelectField';
8
-
9
- const TemplateSearchField = ({
10
- name,
11
- controller,
12
- labelText,
13
- required,
14
- defaultValue,
15
- setValue,
16
- values,
17
- }) => {
18
- const searchQuery = useSelector(
19
- state => state.autocomplete?.[name]?.searchQuery
20
- );
21
- useEffect(() => {
22
- setValue({ ...values, [name]: searchQuery });
23
- // eslint-disable-next-line react-hooks/exhaustive-deps
24
- }, [searchQuery]);
25
- const id = name.replace(/ /g, '-');
26
- return (
27
- <FormGroup
28
- label={name}
29
- labelIcon={helpLabel(labelText, name)}
30
- fieldId={id}
31
- isRequired={required}
32
- className="foreman-search-field"
33
- >
34
- <SearchBar
35
- initialQuery={defaultValue}
36
- data={{
37
- controller,
38
- autocomplete: {
39
- id: name,
40
- url: `/${controller}/auto_complete_search`,
41
- useKeyShortcuts: true,
42
- },
43
- }}
44
- onSearch={() => null}
45
- />
46
- </FormGroup>
47
- );
48
- };
49
-
50
- export const formatter = (input, values, setValue) => {
51
- const isSelectType = !!input?.options;
52
- const inputType = input.value_type;
53
- const isTextType = inputType === 'plain' || !inputType; // null defaults to plain
54
-
55
- const { name, required, hidden_value: hidden } = input;
56
- const labelText = input.description;
57
- const value = values[name];
58
- const id = name.replace(/ /g, '-');
59
- if (isSelectType) {
60
- const options = input.options.split(/\r?\n/).map(option => option.trim());
61
- return (
62
- <SelectField
63
- aria-label={name}
64
- key={id}
65
- isRequired={required}
66
- label={name}
67
- fieldId={id}
68
- options={options}
69
- labelIcon={helpLabel(labelText, name)}
70
- value={value}
71
- setValue={newValue => setValue({ ...values, [name]: newValue })}
72
- />
73
- );
74
- }
75
- if (isTextType) {
76
- return (
77
- <FormGroup
78
- key={name}
79
- label={name}
80
- labelIcon={helpLabel(labelText, name)}
81
- fieldId={id}
82
- isRequired={required}
83
- >
84
- <TextArea
85
- aria-label={name}
86
- className={hidden ? 'masked-input' : null}
87
- required={required}
88
- rows={2}
89
- id={id}
90
- value={value}
91
- onChange={newValue => setValue({ ...values, [name]: newValue })}
92
- />
93
- </FormGroup>
94
- );
95
- }
96
- if (inputType === 'date') {
97
- return (
98
- <FormGroup
99
- key={name}
100
- label={name}
101
- labelIcon={helpLabel(labelText, name)}
102
- fieldId={id}
103
- isRequired={required}
104
- >
105
- <TextInput
106
- aria-label={name}
107
- placeholder="YYYY-mm-dd HH:MM"
108
- className={hidden ? 'masked-input' : null}
109
- required={required}
110
- id={id}
111
- type="text"
112
- value={value}
113
- onChange={newValue => setValue({ ...values, [name]: newValue })}
114
- />
115
- </FormGroup>
116
- );
117
- }
118
- if (inputType === 'search') {
119
- const controller = input.resource_type;
120
- // TODO: get text from redux autocomplete
121
- return (
122
- <TemplateSearchField
123
- key={id}
124
- name={name}
125
- defaultValue={value}
126
- controller={controller}
127
- labelText={labelText}
128
- required={required}
129
- setValue={setValue}
130
- values={values}
131
- />
132
- );
133
- }
134
-
135
- return null;
136
- };
137
-
138
- TemplateSearchField.propTypes = {
139
- name: PropTypes.string.isRequired,
140
- controller: PropTypes.string.isRequired,
141
- labelText: PropTypes.string,
142
- required: PropTypes.bool.isRequired,
143
- defaultValue: PropTypes.string,
144
- setValue: PropTypes.func.isRequired,
145
- values: PropTypes.object.isRequired,
146
- };
147
- TemplateSearchField.defaultProps = {
148
- labelText: null,
149
- defaultValue: '',
150
- };
@@ -1,35 +0,0 @@
1
- import React, { useState } from 'react';
2
- import PropTypes from 'prop-types';
3
- import { FormGroup, TextInput, ValidatedOptions } from '@patternfly/react-core';
4
- import { translate as __ } from 'foremanReact/common/I18n';
5
-
6
- export const NumberInput = ({ formProps, inputProps }) => {
7
- const [validated, setValidated] = useState();
8
- const name = inputProps.id.replace(/-/g, ' ');
9
- return (
10
- <FormGroup
11
- {...formProps}
12
- helperTextInvalid={__('Has to be a number')}
13
- validated={validated}
14
- >
15
- <TextInput
16
- aria-label={name}
17
- type="text"
18
- {...inputProps}
19
- onChange={newValue => {
20
- setValidated(
21
- /^\d+$/.test(newValue) || newValue === ''
22
- ? ValidatedOptions.noval
23
- : ValidatedOptions.error
24
- );
25
- inputProps.onChange(newValue);
26
- }}
27
- />
28
- </FormGroup>
29
- );
30
- };
31
-
32
- NumberInput.propTypes = {
33
- formProps: PropTypes.object.isRequired,
34
- inputProps: PropTypes.object.isRequired,
35
- };
@@ -1,14 +0,0 @@
1
- import React from 'react';
2
- import PropTypes from 'prop-types';
3
- import { Title } from '@patternfly/react-core';
4
-
5
- export const WizardTitle = ({ title, ...props }) => (
6
- <Title headingLevel="h2" className="wizard-title" {...props}>
7
- {title}
8
- </Title>
9
- );
10
-
11
- WizardTitle.propTypes = {
12
- title: PropTypes.string.isRequired,
13
- };
14
- export default WizardTitle;
@@ -1,76 +0,0 @@
1
- import React from 'react';
2
- import { Provider } from 'react-redux';
3
- import configureMockStore from 'redux-mock-store';
4
- import * as patternfly from '@patternfly/react-core';
5
- import { mount, shallow } from '@theforeman/test';
6
- import { formatter } from '../Formatter';
7
-
8
- jest.spyOn(patternfly, 'Select');
9
- jest.spyOn(patternfly, 'SelectOption');
10
- jest.spyOn(patternfly, 'FormGroup');
11
- patternfly.Select.mockImplementation(props => <div props={props} />);
12
- patternfly.SelectOption.mockImplementation(props => <div props={props} />);
13
- patternfly.FormGroup.mockImplementation(props => <div props={props} />);
14
- const mockStore = configureMockStore([]);
15
- const store = mockStore({});
16
-
17
- describe('formatter', () => {
18
- it('render date input', () => {
19
- const props = {
20
- name: 'date adv',
21
- required: false,
22
- options: '',
23
- advanced: true,
24
- value_type: 'date',
25
- resource_type: 'ansible_roles',
26
- default: '',
27
- hidden_value: false,
28
- };
29
- expect(shallow(formatter(props, {}, jest.fn()))).toMatchSnapshot();
30
- });
31
- it('render text input', () => {
32
- const props = {
33
- name: 'plain adv hidden',
34
- required: true,
35
- description: 'some Description',
36
- options: '',
37
- advanced: true,
38
- value_type: 'plain',
39
- resource_type: 'ansible_roles',
40
- default: 'Default val',
41
- hidden_value: true,
42
- };
43
- expect(shallow(formatter(props, {}, jest.fn()))).toMatchSnapshot();
44
- });
45
- it('render select input', () => {
46
- const props = {
47
- name: 'adv plain search',
48
- required: false,
49
- input_type: 'user',
50
- options: 'option 1\r\noption 2\r\noption 3\r\noption 4',
51
- advanced: true,
52
- value_type: 'plain',
53
- resource_type: 'ansible_roles',
54
- default: '',
55
- hidden_value: false,
56
- };
57
- expect(shallow(formatter(props, {}, jest.fn()))).toMatchSnapshot();
58
- });
59
- it('render search input', () => {
60
- const props = {
61
- name: 'search adv',
62
- required: false,
63
- options: '',
64
- advanced: true,
65
- value_type: 'search',
66
- resource_type: 'foreman_tasks/tasks',
67
- default: '',
68
- hidden_value: false,
69
- };
70
- expect(
71
- mount(
72
- <Provider store={store}>{formatter(props, {}, jest.fn())}</Provider>
73
- )
74
- ).toMatchSnapshot();
75
- });
76
- });