foreman_remote_execution 4.3.1 → 4.5.2
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 +27 -22
- data/app/controllers/foreman_remote_execution/concerns/api/v2/registration_commands_controller_extensions.rb +19 -0
- data/app/controllers/job_invocations_controller.rb +1 -1
- data/app/controllers/job_templates_controller.rb +4 -4
- data/app/controllers/ui_job_wizard_controller.rb +19 -0
- data/app/helpers/job_invocations_helper.rb +2 -2
- data/app/helpers/remote_execution_helper.rb +40 -9
- data/app/lib/actions/remote_execution/run_host_job.rb +36 -6
- data/app/lib/foreman_remote_execution/provider_input.rb +29 -0
- data/app/models/concerns/foreman_remote_execution/host_extensions.rb +7 -5
- data/app/models/concerns/foreman_remote_execution/smart_proxy_extensions.rb +6 -0
- data/app/models/host_proxy_invocation.rb +4 -0
- data/app/models/host_status/execution_status.rb +5 -5
- data/app/models/invocation_provider_input_value.rb +12 -0
- data/app/models/job_invocation.rb +35 -12
- data/app/models/job_invocation_composer.rb +74 -19
- data/app/models/remote_execution_provider.rb +18 -3
- data/app/models/setting/remote_execution.rb +11 -1
- data/app/models/ssh_execution_provider.rb +4 -4
- data/app/models/targeting.rb +5 -1
- data/app/models/template_invocation.rb +2 -0
- data/app/overrides/execution_interface.rb +8 -8
- data/app/overrides/subnet_proxies.rb +6 -6
- data/app/services/renderer_methods.rb +12 -0
- data/app/views/job_invocations/_form.html.erb +8 -0
- data/app/views/job_invocations/index.html.erb +1 -1
- data/app/views/templates/ssh/module_action.erb +1 -0
- data/app/views/templates/ssh/puppet_run_once.erb +1 -0
- 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/db/migrate/20210312074713_add_provider_inputs.rb +10 -0
- data/db/migrate/2021051713291621250977_add_host_proxy_invocations.rb +12 -0
- data/extra/cockpit/foreman-cockpit-session +6 -6
- data/foreman_remote_execution.gemspec +1 -1
- data/lib/foreman_remote_execution/engine.rb +14 -12
- data/lib/foreman_remote_execution/version.rb +1 -1
- data/locale/action_names.rb +1 -0
- data/locale/de/foreman_remote_execution.po +77 -27
- data/locale/en/foreman_remote_execution.po +77 -27
- data/locale/en_GB/foreman_remote_execution.po +77 -27
- data/locale/es/foreman_remote_execution.po +77 -27
- data/locale/foreman_remote_execution.pot +241 -163
- data/locale/fr/foreman_remote_execution.po +77 -27
- data/locale/ja/foreman_remote_execution.po +77 -27
- data/locale/ko/foreman_remote_execution.po +77 -27
- data/locale/pt_BR/foreman_remote_execution.po +77 -27
- data/locale/ru/foreman_remote_execution.po +77 -27
- data/locale/zh_CN/foreman_remote_execution.po +77 -27
- data/locale/zh_TW/foreman_remote_execution.po +77 -27
- data/package.json +4 -2
- data/test/functional/api/v2/job_invocations_controller_test.rb +14 -1
- data/test/helpers/remote_execution_helper_test.rb +16 -0
- data/test/unit/job_invocation_composer_test.rb +100 -3
- data/test/unit/job_invocation_report_template_test.rb +57 -0
- data/test/unit/job_invocation_test.rb +1 -1
- data/webpack/JobWizard/JobWizard.js +95 -11
- data/webpack/JobWizard/JobWizard.scss +53 -0
- data/webpack/JobWizard/JobWizardConstants.js +16 -0
- data/webpack/JobWizard/JobWizardSelectors.js +47 -0
- data/webpack/JobWizard/__tests__/__snapshots__/integration.test.js.snap +43 -0
- data/webpack/JobWizard/__tests__/fixtures.js +128 -0
- data/webpack/JobWizard/__tests__/integration.test.js +84 -0
- data/webpack/JobWizard/steps/AdvancedFields/AdvancedFields.js +110 -0
- data/webpack/JobWizard/steps/AdvancedFields/DescriptionField.js +67 -0
- data/webpack/JobWizard/steps/AdvancedFields/Fields.js +195 -0
- data/webpack/JobWizard/steps/AdvancedFields/__tests__/AdvancedFields.test.js +144 -0
- data/webpack/JobWizard/steps/AdvancedFields/__tests__/DescriptionField.test.js +23 -0
- data/webpack/JobWizard/steps/CategoryAndTemplate/CategoryAndTemplate.js +109 -0
- data/webpack/JobWizard/steps/CategoryAndTemplate/CategoryAndTemplate.test.js +123 -0
- data/webpack/JobWizard/steps/CategoryAndTemplate/index.js +94 -0
- data/webpack/JobWizard/steps/Schedule/QueryType.js +48 -0
- data/webpack/JobWizard/steps/Schedule/RepeatOn.js +61 -0
- data/webpack/JobWizard/steps/Schedule/ScheduleType.js +25 -0
- data/webpack/JobWizard/steps/Schedule/StartEndDates.js +51 -0
- data/webpack/JobWizard/steps/Schedule/__tests__/StartEndDates.test.js +22 -0
- data/webpack/JobWizard/steps/Schedule/index.js +41 -0
- data/webpack/JobWizard/steps/form/FormHelpers.js +20 -0
- data/webpack/JobWizard/steps/form/Formatter.js +149 -0
- data/webpack/JobWizard/steps/form/GroupedSelectField.js +91 -0
- data/webpack/JobWizard/steps/form/NumberInput.js +33 -0
- data/webpack/JobWizard/steps/form/SelectField.js +60 -0
- data/webpack/JobWizard/steps/form/__tests__/Formatter.test.js.example +76 -0
- data/webpack/__mocks__/foremanReact/common/helpers.js +1 -0
- data/webpack/__mocks__/foremanReact/components/SearchBar.js +18 -1
- data/webpack/__mocks__/foremanReact/redux/API/APISelectors.js +21 -2
- data/webpack/__mocks__/foremanReact/redux/API/index.js +5 -0
- data/webpack/__mocks__/foremanReact/routes/common/PageLayout/PageLayout.js +10 -0
- data/webpack/global_index.js +6 -0
- data/webpack/index.js +3 -4
- data/webpack/react_app/components/RecentJobsCard/RecentJobsCard.js +83 -0
- data/webpack/react_app/components/RecentJobsCard/constants.js +1 -0
- data/webpack/react_app/components/RecentJobsCard/index.js +1 -0
- data/webpack/react_app/components/RecentJobsCard/styles.css +15 -0
- data/webpack/react_app/components/RegistrationExtension/RexInterface.js +50 -0
- data/webpack/react_app/components/RegistrationExtension/__tests__/RexInterface.test.js +9 -0
- data/webpack/react_app/components/RegistrationExtension/__tests__/__snapshots__/RexInterface.test.js.snap +35 -0
- data/webpack/react_app/components/TargetingHosts/__tests__/TargetingHostsSelectors.test.js +8 -3
- data/webpack/react_app/components/TargetingHosts/__tests__/__snapshots__/TargetingHostsPage.test.js.snap +1 -0
- data/webpack/react_app/components/TargetingHosts/__tests__/__snapshots__/TargetingHostsSelectors.test.js.snap +7 -2
- data/webpack/react_app/extend/fillRecentJobsCard.js +11 -0
- data/webpack/react_app/extend/fillregistrationAdvanced.js +11 -0
- data/webpack/react_app/extend/reducers.js +5 -0
- metadata +52 -8
- data/app/models/concerns/foreman_remote_execution/orchestration/ssh.rb +0 -70
- data/app/views/api/v2/registration/_form.html.erb +0 -12
- data/test/models/orchestration/ssh_test.rb +0 -56
|
@@ -0,0 +1,33 @@
|
|
|
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
|
+
return (
|
|
9
|
+
<FormGroup
|
|
10
|
+
{...formProps}
|
|
11
|
+
helperTextInvalid={__('Has to be a number')}
|
|
12
|
+
validated={validated}
|
|
13
|
+
>
|
|
14
|
+
<TextInput
|
|
15
|
+
type="text"
|
|
16
|
+
{...inputProps}
|
|
17
|
+
onChange={newValue => {
|
|
18
|
+
setValidated(
|
|
19
|
+
/^\d+$/.test(newValue) || newValue === ''
|
|
20
|
+
? ValidatedOptions.noval
|
|
21
|
+
: ValidatedOptions.error
|
|
22
|
+
);
|
|
23
|
+
inputProps.onChange(newValue);
|
|
24
|
+
}}
|
|
25
|
+
/>
|
|
26
|
+
</FormGroup>
|
|
27
|
+
);
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
NumberInput.propTypes = {
|
|
31
|
+
formProps: PropTypes.object.isRequired,
|
|
32
|
+
inputProps: PropTypes.object.isRequired,
|
|
33
|
+
};
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import React, { useState } from 'react';
|
|
2
|
+
import { FormGroup, Select, SelectOption } from '@patternfly/react-core';
|
|
3
|
+
import PropTypes from 'prop-types';
|
|
4
|
+
|
|
5
|
+
export const SelectField = ({
|
|
6
|
+
label,
|
|
7
|
+
fieldId,
|
|
8
|
+
options,
|
|
9
|
+
value,
|
|
10
|
+
setValue,
|
|
11
|
+
labelIcon,
|
|
12
|
+
isRequired,
|
|
13
|
+
...props
|
|
14
|
+
}) => {
|
|
15
|
+
const onSelect = (event, selection) => {
|
|
16
|
+
setValue(selection);
|
|
17
|
+
setIsOpen(false);
|
|
18
|
+
};
|
|
19
|
+
const [isOpen, setIsOpen] = useState(false);
|
|
20
|
+
return (
|
|
21
|
+
<FormGroup
|
|
22
|
+
label={label}
|
|
23
|
+
fieldId={fieldId}
|
|
24
|
+
labelIcon={labelIcon}
|
|
25
|
+
isRequired={isRequired}
|
|
26
|
+
>
|
|
27
|
+
<Select
|
|
28
|
+
selections={value}
|
|
29
|
+
onSelect={onSelect}
|
|
30
|
+
onToggle={setIsOpen}
|
|
31
|
+
isOpen={isOpen}
|
|
32
|
+
className="without_select2"
|
|
33
|
+
maxHeight="45vh"
|
|
34
|
+
menuAppendTo={() => document.body}
|
|
35
|
+
{...props}
|
|
36
|
+
>
|
|
37
|
+
{options.map((option, index) => (
|
|
38
|
+
<SelectOption key={index} value={option} />
|
|
39
|
+
))}
|
|
40
|
+
</Select>
|
|
41
|
+
</FormGroup>
|
|
42
|
+
);
|
|
43
|
+
};
|
|
44
|
+
SelectField.propTypes = {
|
|
45
|
+
label: PropTypes.string,
|
|
46
|
+
fieldId: PropTypes.string.isRequired,
|
|
47
|
+
options: PropTypes.array,
|
|
48
|
+
value: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),
|
|
49
|
+
setValue: PropTypes.func.isRequired,
|
|
50
|
+
labelIcon: PropTypes.node,
|
|
51
|
+
isRequired: PropTypes.bool,
|
|
52
|
+
};
|
|
53
|
+
|
|
54
|
+
SelectField.defaultProps = {
|
|
55
|
+
label: null,
|
|
56
|
+
options: [],
|
|
57
|
+
labelIcon: null,
|
|
58
|
+
value: null,
|
|
59
|
+
isRequired: false,
|
|
60
|
+
};
|
|
@@ -0,0 +1,76 @@
|
|
|
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
|
+
});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export const foremanUrl = path => `foreman${path}`;
|
|
@@ -1,2 +1,19 @@
|
|
|
1
|
-
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import PropTypes from 'prop-types';
|
|
3
|
+
|
|
4
|
+
const SearchBar = ({ onChange }) => (
|
|
5
|
+
<input
|
|
6
|
+
className="foreman-search"
|
|
7
|
+
onChange={onChange}
|
|
8
|
+
placeholder="Filter..."
|
|
9
|
+
/>
|
|
10
|
+
);
|
|
2
11
|
export default SearchBar;
|
|
12
|
+
|
|
13
|
+
SearchBar.propTypes = {
|
|
14
|
+
onChange: PropTypes.func,
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
SearchBar.defaultProps = {
|
|
18
|
+
onChange: () => null,
|
|
19
|
+
};
|
|
@@ -1,2 +1,21 @@
|
|
|
1
|
-
export const
|
|
2
|
-
export const
|
|
1
|
+
export const selectAPI = state => state;
|
|
2
|
+
export const selectAPIByKey = (state, key) => selectAPI(state)[key] || {};
|
|
3
|
+
|
|
4
|
+
export const selectAPIStatus = (state, key) =>
|
|
5
|
+
selectAPIByKey(state, key).status;
|
|
6
|
+
|
|
7
|
+
export const selectAPIPayload = (state, key) =>
|
|
8
|
+
selectAPIByKey(state, key).payload || {};
|
|
9
|
+
|
|
10
|
+
export const selectAPIResponse = (state, key) =>
|
|
11
|
+
selectAPIByKey(state, key).response || {};
|
|
12
|
+
|
|
13
|
+
export const selectAPIError = (state, key) =>
|
|
14
|
+
selectAPIStatus(state, key) === 'ERROR'
|
|
15
|
+
? selectAPIResponse(state, key)
|
|
16
|
+
: null;
|
|
17
|
+
|
|
18
|
+
export const selectAPIErrorMessage = (state, key) => {
|
|
19
|
+
const error = selectAPIError(state, key);
|
|
20
|
+
return error && error.message;
|
|
21
|
+
};
|
data/webpack/global_index.js
CHANGED
|
@@ -1,4 +1,10 @@
|
|
|
1
1
|
import { registerRoutes } from 'foremanReact/routes/RoutingService';
|
|
2
2
|
import routes from './Routes/routes';
|
|
3
|
+
import fillregistrationAdvanced from './react_app/extend/fillregistrationAdvanced';
|
|
4
|
+
import fillRecentJobsCard from './react_app/extend/fillRecentJobsCard';
|
|
5
|
+
import registerReducers from './react_app/extend/reducers';
|
|
3
6
|
|
|
7
|
+
registerReducers();
|
|
4
8
|
registerRoutes('foreman_remote_execution', routes);
|
|
9
|
+
fillRecentJobsCard();
|
|
10
|
+
fillregistrationAdvanced();
|
data/webpack/index.js
CHANGED
|
@@ -1,8 +1,9 @@
|
|
|
1
|
-
import { registerReducer } from 'foremanReact/common/MountingService';
|
|
2
1
|
import componentRegistry from 'foremanReact/components/componentRegistry';
|
|
3
2
|
import JobInvocationContainer from './react_app/components/jobInvocations';
|
|
4
3
|
import TargetingHosts from './react_app/components/TargetingHosts';
|
|
5
|
-
import
|
|
4
|
+
import registerReducers from './react_app/extend/reducers';
|
|
5
|
+
|
|
6
|
+
registerReducers();
|
|
6
7
|
|
|
7
8
|
const components = [
|
|
8
9
|
{ name: 'JobInvocationContainer', type: JobInvocationContainer },
|
|
@@ -12,5 +13,3 @@ const components = [
|
|
|
12
13
|
components.forEach(component => {
|
|
13
14
|
componentRegistry.register(component);
|
|
14
15
|
});
|
|
15
|
-
|
|
16
|
-
registerReducer('foremanRemoteExecutionReducers', rootReducer);
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
/* eslint-disable camelcase */
|
|
2
|
+
|
|
3
|
+
import PropTypes from 'prop-types';
|
|
4
|
+
import React from 'react';
|
|
5
|
+
import Skeleton from 'react-loading-skeleton';
|
|
6
|
+
import ElipsisWithTooltip from 'react-ellipsis-with-tooltip';
|
|
7
|
+
|
|
8
|
+
import { Grid, GridItem } from '@patternfly/react-core';
|
|
9
|
+
import {
|
|
10
|
+
PropertiesSidePanel,
|
|
11
|
+
PropertyItem,
|
|
12
|
+
} from '@patternfly/react-catalog-view-extension';
|
|
13
|
+
import { ArrowIcon, ErrorCircleOIcon, OkIcon } from '@patternfly/react-icons';
|
|
14
|
+
|
|
15
|
+
import { useAPI } from 'foremanReact/common/hooks/API/APIHooks';
|
|
16
|
+
import CardItem from 'foremanReact/components/HostDetails/Templates/CardItem/CardTemplate';
|
|
17
|
+
import RelativeDateTime from 'foremanReact/components/common/dates/RelativeDateTime';
|
|
18
|
+
import { translate as __ } from 'foremanReact/common/I18n';
|
|
19
|
+
import './styles.css';
|
|
20
|
+
|
|
21
|
+
const RecentJobsCard = ({ hostDetails: { name } }) => {
|
|
22
|
+
const jobsUrl =
|
|
23
|
+
name && `/api/job_invocations?search=host%3D${name}&per_page=3`;
|
|
24
|
+
const {
|
|
25
|
+
response: { results: jobs },
|
|
26
|
+
} = useAPI('get', jobsUrl);
|
|
27
|
+
|
|
28
|
+
const iconMarkup = status => {
|
|
29
|
+
if (status === 1) return <ErrorCircleOIcon color="#C9190B" />;
|
|
30
|
+
return <OkIcon color="#3E8635" />;
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
return (
|
|
34
|
+
<CardItem
|
|
35
|
+
header={
|
|
36
|
+
<span>
|
|
37
|
+
{__('Recent Jobs')}{' '}
|
|
38
|
+
<a href={`/job_invocations?search=host+%3D+${name}`}>
|
|
39
|
+
<ArrowIcon />
|
|
40
|
+
</a>
|
|
41
|
+
</span>
|
|
42
|
+
}
|
|
43
|
+
>
|
|
44
|
+
<PropertiesSidePanel>
|
|
45
|
+
{jobs?.map(({ status, status_label, id, start_at, description }) => (
|
|
46
|
+
<PropertyItem
|
|
47
|
+
key={id}
|
|
48
|
+
label={
|
|
49
|
+
description ? (
|
|
50
|
+
<Grid>
|
|
51
|
+
<GridItem span={8}>
|
|
52
|
+
<ElipsisWithTooltip>{description}</ElipsisWithTooltip>
|
|
53
|
+
</GridItem>
|
|
54
|
+
<GridItem span={1}>{iconMarkup(status)}</GridItem>
|
|
55
|
+
<GridItem span={3}>{status_label}</GridItem>
|
|
56
|
+
</Grid>
|
|
57
|
+
) : (
|
|
58
|
+
<Skeleton />
|
|
59
|
+
)
|
|
60
|
+
}
|
|
61
|
+
value={
|
|
62
|
+
start_at ? (
|
|
63
|
+
<a href={`/job_invocations/${id}`}>
|
|
64
|
+
<RelativeDateTime date={start_at} />
|
|
65
|
+
</a>
|
|
66
|
+
) : (
|
|
67
|
+
<Skeleton />
|
|
68
|
+
)
|
|
69
|
+
}
|
|
70
|
+
/>
|
|
71
|
+
))}
|
|
72
|
+
</PropertiesSidePanel>
|
|
73
|
+
</CardItem>
|
|
74
|
+
);
|
|
75
|
+
};
|
|
76
|
+
|
|
77
|
+
export default RecentJobsCard;
|
|
78
|
+
|
|
79
|
+
RecentJobsCard.propTypes = {
|
|
80
|
+
hostDetails: PropTypes.shape({
|
|
81
|
+
name: PropTypes.string,
|
|
82
|
+
}).isRequired,
|
|
83
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export const HOST_DETAILS_JOBS = 'HOST_DETAILS_JOBS';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { default } from './RecentJobsCard';
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
.properties-side-panel-pf-property-value {
|
|
2
|
+
font-size: 14px !important;
|
|
3
|
+
margin-top: 8px;
|
|
4
|
+
word-break: break-word;
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
.properties-side-panel-pf-property-label {
|
|
8
|
+
font-weight: 700 !important;
|
|
9
|
+
font-size: 14px !important;
|
|
10
|
+
margin: 0 !important;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
.properties-side-panel-pf-property {
|
|
14
|
+
margin-top: 24px;
|
|
15
|
+
}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import PropTypes from 'prop-types';
|
|
3
|
+
|
|
4
|
+
import { translate as __ } from 'foremanReact/common/I18n';
|
|
5
|
+
|
|
6
|
+
import { FormGroup, TextInput, Popover } from '@patternfly/react-core';
|
|
7
|
+
|
|
8
|
+
import { HelpIcon } from '@patternfly/react-icons';
|
|
9
|
+
|
|
10
|
+
const RexInterface = ({ isLoading, onChange }) => (
|
|
11
|
+
<FormGroup
|
|
12
|
+
label={__('Remote Execution Interface')}
|
|
13
|
+
fieldId="reg_rex_interface"
|
|
14
|
+
labelIcon={
|
|
15
|
+
<Popover
|
|
16
|
+
bodyContent={
|
|
17
|
+
<div>
|
|
18
|
+
{__('Identifier of the Host interface for Remote execution')}
|
|
19
|
+
</div>
|
|
20
|
+
}
|
|
21
|
+
>
|
|
22
|
+
<button
|
|
23
|
+
className="pf-c-form__group-label-help"
|
|
24
|
+
onClick={e => e.preventDefault()}
|
|
25
|
+
>
|
|
26
|
+
<HelpIcon noVerticalAlign />
|
|
27
|
+
</button>
|
|
28
|
+
</Popover>
|
|
29
|
+
}
|
|
30
|
+
>
|
|
31
|
+
<TextInput
|
|
32
|
+
type="text"
|
|
33
|
+
onBlur={e => onChange({ remoteExecutionInterface: e.target.value })}
|
|
34
|
+
id="reg_rex_interface_input"
|
|
35
|
+
isDisabled={isLoading}
|
|
36
|
+
/>
|
|
37
|
+
</FormGroup>
|
|
38
|
+
);
|
|
39
|
+
|
|
40
|
+
RexInterface.propTypes = {
|
|
41
|
+
onChange: PropTypes.func,
|
|
42
|
+
isLoading: PropTypes.bool,
|
|
43
|
+
};
|
|
44
|
+
|
|
45
|
+
RexInterface.defaultProps = {
|
|
46
|
+
onChange: undefined,
|
|
47
|
+
isLoading: false,
|
|
48
|
+
};
|
|
49
|
+
|
|
50
|
+
export default RexInterface;
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { testComponentSnapshotsWithFixtures } from '@theforeman/test';
|
|
2
|
+
import RexInterface from '../RexInterface';
|
|
3
|
+
|
|
4
|
+
const fixtures = {
|
|
5
|
+
renders: { isLoading: false, onChange: () => {} },
|
|
6
|
+
};
|
|
7
|
+
|
|
8
|
+
describe('RexInterface', () =>
|
|
9
|
+
testComponentSnapshotsWithFixtures(RexInterface, fixtures));
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
|
2
|
+
|
|
3
|
+
exports[`RexInterface renders 1`] = `
|
|
4
|
+
<FormGroup
|
|
5
|
+
fieldId="reg_rex_interface"
|
|
6
|
+
label="Remote Execution Interface"
|
|
7
|
+
labelIcon={
|
|
8
|
+
<Popover
|
|
9
|
+
bodyContent={
|
|
10
|
+
<div>
|
|
11
|
+
Identifier of the Host interface for Remote execution
|
|
12
|
+
</div>
|
|
13
|
+
}
|
|
14
|
+
>
|
|
15
|
+
<button
|
|
16
|
+
className="pf-c-form__group-label-help"
|
|
17
|
+
onClick={[Function]}
|
|
18
|
+
>
|
|
19
|
+
<HelpIcon
|
|
20
|
+
color="currentColor"
|
|
21
|
+
noVerticalAlign={true}
|
|
22
|
+
size="sm"
|
|
23
|
+
/>
|
|
24
|
+
</button>
|
|
25
|
+
</Popover>
|
|
26
|
+
}
|
|
27
|
+
>
|
|
28
|
+
<TextInput
|
|
29
|
+
id="reg_rex_interface_input"
|
|
30
|
+
isDisabled={false}
|
|
31
|
+
onBlur={[Function]}
|
|
32
|
+
type="text"
|
|
33
|
+
/>
|
|
34
|
+
</FormGroup>
|
|
35
|
+
`;
|