foreman_remote_execution 4.2.2 → 4.5.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.github/workflows/js_ci.yml +29 -0
- data/.github/workflows/{ci.yml → ruby_ci.yml} +22 -50
- data/.prettierrc +4 -0
- data/.rubocop.yml +13 -49
- data/.rubocop_todo.yml +326 -102
- data/Gemfile +1 -4
- data/app/controllers/api/v2/job_invocations_controller.rb +28 -23
- data/app/controllers/foreman_remote_execution/concerns/api/v2/registration_commands_controller_extensions.rb +19 -0
- data/app/controllers/job_templates_controller.rb +4 -4
- data/app/controllers/ui_job_wizard_controller.rb +30 -0
- data/app/helpers/job_invocations_helper.rb +2 -2
- data/app/helpers/remote_execution_helper.rb +35 -8
- data/app/lib/actions/remote_execution/run_host_job.rb +68 -5
- data/app/lib/foreman_remote_execution/provider_input.rb +29 -0
- data/app/lib/foreman_remote_execution/renderer/scope/input.rb +1 -0
- data/app/models/concerns/foreman_remote_execution/host_extensions.rb +5 -5
- data/app/models/host_status/execution_status.rb +12 -5
- data/app/models/invocation_provider_input_value.rb +12 -0
- data/app/models/job_invocation.rb +28 -8
- data/app/models/job_invocation_composer.rb +72 -17
- data/app/models/remote_execution_provider.rb +17 -2
- data/app/models/setting/remote_execution.rb +10 -0
- data/app/models/ssh_execution_provider.rb +4 -4
- 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/template_invocations/show.html.erb +30 -23
- data/config/routes.rb +5 -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/extra/cockpit/foreman-cockpit-session +6 -6
- data/foreman_remote_execution.gemspec +1 -2
- data/lib/foreman_remote_execution/engine.rb +22 -7
- data/lib/foreman_remote_execution/version.rb +1 -1
- data/lib/tasks/foreman_remote_execution_tasks.rake +1 -18
- 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 +38 -5
- data/test/functional/api/v2/registration_controller_test.rb +4 -13
- data/test/functional/ui_job_wizard_controller_test.rb +16 -0
- data/test/helpers/remote_execution_helper_test.rb +16 -0
- data/test/unit/job_invocation_composer_test.rb +86 -2
- data/test/unit/job_invocation_report_template_test.rb +57 -0
- data/webpack/JobWizard/JobWizard.js +96 -0
- data/webpack/JobWizard/JobWizard.scss +14 -0
- data/webpack/JobWizard/JobWizardConstants.js +6 -0
- data/webpack/JobWizard/JobWizardSelectors.js +38 -0
- data/webpack/JobWizard/__tests__/JobWizard.test.js +13 -0
- data/webpack/JobWizard/__tests__/__snapshots__/JobWizard.test.js.snap +32 -0
- 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/index.js +32 -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 +109 -0
- data/webpack/JobWizard/steps/CategoryAndTemplate/CategoryAndTemplate.test.js +52 -0
- data/webpack/JobWizard/steps/CategoryAndTemplate/__snapshots__/CategoryAndTemplate.test.js.snap +113 -0
- data/webpack/JobWizard/steps/CategoryAndTemplate/index.js +94 -0
- data/webpack/JobWizard/steps/form/FormHelpers.js +19 -0
- data/webpack/JobWizard/steps/form/GroupedSelectField.js +91 -0
- data/webpack/JobWizard/steps/form/SelectField.js +48 -0
- data/webpack/JobWizard/steps/form/__tests__/GroupedSelectField.test.js +38 -0
- data/webpack/JobWizard/steps/form/__tests__/SelectField.test.js +23 -0
- data/webpack/JobWizard/steps/form/__tests__/__snapshots__/GroupedSelectField.test.js.snap +37 -0
- data/webpack/JobWizard/steps/form/__tests__/__snapshots__/SelectField.test.js.snap +23 -0
- data/webpack/Routes/routes.js +12 -0
- data/webpack/__mocks__/foremanReact/common/helpers.js +1 -0
- data/webpack/__mocks__/foremanReact/history.js +1 -0
- 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 +10 -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/TargetingHostsPage.js +1 -1
- data/webpack/react_app/components/TargetingHosts/TargetingHostsPage.scss +0 -3
- 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 -1
- 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 +58 -20
- data/app/views/api/v2/registration/_form.html.erb +0 -12
@@ -0,0 +1,26 @@
|
|
1
|
+
const jobTemplate = {
|
2
|
+
id: 178,
|
3
|
+
name: 'Run Command - Ansible Default',
|
4
|
+
template:
|
5
|
+
"---\n- hosts: all\n tasks:\n - shell:\n cmd: |\n<%= indent(10) { input('command') } %>\n register: out\n - debug: var=out",
|
6
|
+
snippet: false,
|
7
|
+
default: true,
|
8
|
+
job_category: 'Ansible Commands',
|
9
|
+
provider_type: 'Ansible',
|
10
|
+
description_format: 'Run %{command}',
|
11
|
+
execution_timeout_interval: 2,
|
12
|
+
description: null,
|
13
|
+
};
|
14
|
+
|
15
|
+
export const jobTemplates = [jobTemplate];
|
16
|
+
|
17
|
+
export const jobTemplateResponse = {
|
18
|
+
job_template: jobTemplate,
|
19
|
+
effective_user: {
|
20
|
+
id: null,
|
21
|
+
job_template_id: 178,
|
22
|
+
value: 'default effective user',
|
23
|
+
overridable: true,
|
24
|
+
current_user: false,
|
25
|
+
},
|
26
|
+
};
|
@@ -0,0 +1,156 @@
|
|
1
|
+
import React from 'react';
|
2
|
+
import { Provider } from 'react-redux';
|
3
|
+
import configureMockStore from 'redux-mock-store';
|
4
|
+
import { mount } from '@theforeman/test';
|
5
|
+
import { render, fireEvent, screen, act } from '@testing-library/react';
|
6
|
+
import * as api from 'foremanReact/redux/API';
|
7
|
+
import { JobWizard } from '../JobWizard';
|
8
|
+
import * as selectors from '../JobWizardSelectors';
|
9
|
+
import { jobTemplates, jobTemplateResponse as jobTemplate } from './fixtures';
|
10
|
+
|
11
|
+
jest.spyOn(api, 'get');
|
12
|
+
jest.spyOn(selectors, 'selectJobTemplate');
|
13
|
+
jest.spyOn(selectors, 'selectJobTemplates');
|
14
|
+
jest.spyOn(selectors, 'selectJobCategories');
|
15
|
+
jest.spyOn(selectors, 'selectJobCategoriesStatus');
|
16
|
+
|
17
|
+
const jobCategories = ['Ansible Commands', 'Puppet', 'Services'];
|
18
|
+
|
19
|
+
api.get.mockImplementation(({ handleSuccess, ...action }) => {
|
20
|
+
if (action.key === 'JOB_CATEGORIES') {
|
21
|
+
handleSuccess && handleSuccess({ data: { job_categories: jobCategories } });
|
22
|
+
} else if (action.key === 'JOB_TEMPLATE') {
|
23
|
+
handleSuccess &&
|
24
|
+
handleSuccess({
|
25
|
+
data: jobTemplate,
|
26
|
+
});
|
27
|
+
}
|
28
|
+
return { type: 'get', ...action };
|
29
|
+
});
|
30
|
+
|
31
|
+
selectors.selectJobTemplate.mockImplementation(() => null);
|
32
|
+
selectors.selectJobCategories.mockImplementation(() => jobCategories);
|
33
|
+
selectors.selectJobCategoriesStatus.mockImplementation(() => null);
|
34
|
+
selectors.selectJobTemplates.mockImplementation(() => jobTemplates);
|
35
|
+
|
36
|
+
const mockStore = configureMockStore([]);
|
37
|
+
const store = mockStore({});
|
38
|
+
describe('Job wizard fill', () => {
|
39
|
+
it('should select template', async () => {
|
40
|
+
const wrapper = mount(
|
41
|
+
<Provider store={store}>
|
42
|
+
<JobWizard advancedValues={{}} setAdvancedValues={jest.fn()} />
|
43
|
+
</Provider>
|
44
|
+
);
|
45
|
+
expect(wrapper.find('.pf-c-wizard__nav-link.pf-m-disabled')).toHaveLength(
|
46
|
+
4
|
47
|
+
);
|
48
|
+
selectors.selectJobCategoriesStatus.mockImplementation(() => 'RESOLVED');
|
49
|
+
expect(store.getActions()).toMatchSnapshot('initial');
|
50
|
+
|
51
|
+
selectors.selectJobTemplate.mockImplementation(() => jobTemplate);
|
52
|
+
wrapper.find('.pf-c-button.pf-c-select__toggle-button').simulate('click');
|
53
|
+
await act(async () => {
|
54
|
+
await wrapper.find('.pf-c-select__menu-item').simulate('click');
|
55
|
+
await wrapper.update();
|
56
|
+
});
|
57
|
+
expect(store.getActions().slice(-1)).toMatchSnapshot('select template');
|
58
|
+
expect(wrapper.find('.pf-c-wizard__nav-link.pf-m-disabled')).toHaveLength(
|
59
|
+
0
|
60
|
+
);
|
61
|
+
});
|
62
|
+
|
63
|
+
it('should save data between steps for advanced fields', async () => {
|
64
|
+
const wrapper = mount(
|
65
|
+
<Provider store={store}>
|
66
|
+
<JobWizard advancedValues={{}} setAdvancedValues={jest.fn()} />
|
67
|
+
</Provider>
|
68
|
+
);
|
69
|
+
// setup
|
70
|
+
selectors.selectJobCategoriesStatus.mockImplementation(() => 'RESOLVED');
|
71
|
+
selectors.selectJobTemplate.mockImplementation(() => jobTemplate);
|
72
|
+
wrapper.find('.pf-c-button.pf-c-select__toggle-button').simulate('click');
|
73
|
+
wrapper.find('.pf-c-select__menu-item').simulate('click');
|
74
|
+
|
75
|
+
// test
|
76
|
+
expect(wrapper.find('.pf-c-wizard__nav-link.pf-m-disabled')).toHaveLength(
|
77
|
+
0
|
78
|
+
);
|
79
|
+
wrapper
|
80
|
+
.find('.pf-c-wizard__nav-link')
|
81
|
+
.at(2)
|
82
|
+
.simulate('click'); // Advanced step
|
83
|
+
const effectiveUserInput = () => wrapper.find('input#effective-user');
|
84
|
+
const effectiveUesrValue = 'effective user new value';
|
85
|
+
effectiveUserInput().getDOMNode().value = effectiveUesrValue;
|
86
|
+
await act(async () => {
|
87
|
+
await effectiveUserInput().simulate('change');
|
88
|
+
wrapper.update();
|
89
|
+
});
|
90
|
+
|
91
|
+
expect(effectiveUserInput().prop('value')).toEqual(effectiveUesrValue);
|
92
|
+
|
93
|
+
wrapper
|
94
|
+
.find('.pf-c-wizard__nav-link')
|
95
|
+
.at(1)
|
96
|
+
.simulate('click');
|
97
|
+
|
98
|
+
expect(wrapper.find('.pf-c-wizard__nav-link.pf-m-current').text()).toEqual(
|
99
|
+
'Target Hosts'
|
100
|
+
);
|
101
|
+
wrapper
|
102
|
+
.find('.pf-c-wizard__nav-link')
|
103
|
+
.at(2)
|
104
|
+
.simulate('click'); // Advanced step
|
105
|
+
|
106
|
+
expect(effectiveUserInput().prop('value')).toEqual(effectiveUesrValue);
|
107
|
+
});
|
108
|
+
|
109
|
+
it('have all steps', async () => {
|
110
|
+
selectors.selectJobCategoriesStatus.mockImplementation(() => null);
|
111
|
+
selectors.selectJobTemplate.mockRestore();
|
112
|
+
selectors.selectJobTemplates.mockRestore();
|
113
|
+
selectors.selectJobCategories.mockRestore();
|
114
|
+
api.get.mockImplementation(({ handleSuccess, ...action }) => {
|
115
|
+
if (action.key === 'JOB_CATEGORIES') {
|
116
|
+
handleSuccess &&
|
117
|
+
handleSuccess({ data: { job_categories: jobCategories } });
|
118
|
+
} else if (action.key === 'JOB_TEMPLATE') {
|
119
|
+
handleSuccess &&
|
120
|
+
handleSuccess({
|
121
|
+
data: jobTemplate,
|
122
|
+
});
|
123
|
+
} else if (action.key === 'JOB_TEMPLATES') {
|
124
|
+
handleSuccess &&
|
125
|
+
handleSuccess({
|
126
|
+
data: { results: [jobTemplate.job_template] },
|
127
|
+
});
|
128
|
+
}
|
129
|
+
return { type: 'get', ...action };
|
130
|
+
});
|
131
|
+
|
132
|
+
render(
|
133
|
+
<Provider store={store}>
|
134
|
+
<JobWizard />
|
135
|
+
</Provider>
|
136
|
+
);
|
137
|
+
const steps = [
|
138
|
+
'Target Hosts',
|
139
|
+
'Advanced Fields',
|
140
|
+
'Schedule',
|
141
|
+
'Review Details',
|
142
|
+
'Category and Template',
|
143
|
+
];
|
144
|
+
// eslint-disable-next-line no-unused-vars
|
145
|
+
for await (const step of steps) {
|
146
|
+
const stepSelector = screen.getByText(step);
|
147
|
+
const stepTitle = screen.getAllByText(step);
|
148
|
+
expect(stepTitle).toHaveLength(1);
|
149
|
+
await act(async () => {
|
150
|
+
await fireEvent.click(stepSelector);
|
151
|
+
});
|
152
|
+
const stepTitles = screen.getAllByText(step);
|
153
|
+
expect(stepTitles).toHaveLength(3);
|
154
|
+
}
|
155
|
+
});
|
156
|
+
});
|
@@ -0,0 +1,32 @@
|
|
1
|
+
import React from 'react';
|
2
|
+
import { Title, Divider } from '@patternfly/react-core';
|
3
|
+
import { translate as __ } from 'foremanReact/common/I18n';
|
4
|
+
import PageLayout from 'foremanReact/routes/common/PageLayout/PageLayout';
|
5
|
+
import { JobWizard } from './JobWizard';
|
6
|
+
|
7
|
+
const JobWizardPage = () => {
|
8
|
+
const title = __('Run job');
|
9
|
+
const breadcrumbOptions = {
|
10
|
+
breadcrumbItems: [
|
11
|
+
{ caption: __('Jobs'), url: `/jobs` },
|
12
|
+
{ caption: title },
|
13
|
+
],
|
14
|
+
};
|
15
|
+
return (
|
16
|
+
<PageLayout
|
17
|
+
header={title}
|
18
|
+
breadcrumbOptions={breadcrumbOptions}
|
19
|
+
searchable={false}
|
20
|
+
>
|
21
|
+
<React.Fragment>
|
22
|
+
<Title headingLevel="h2" size="2xl">
|
23
|
+
{title}
|
24
|
+
</Title>
|
25
|
+
<Divider component="div" />
|
26
|
+
<JobWizard />
|
27
|
+
</React.Fragment>
|
28
|
+
</PageLayout>
|
29
|
+
);
|
30
|
+
};
|
31
|
+
|
32
|
+
export default JobWizardPage;
|
@@ -0,0 +1,93 @@
|
|
1
|
+
import React from 'react';
|
2
|
+
import PropTypes from 'prop-types';
|
3
|
+
import { useSelector } from 'react-redux';
|
4
|
+
import { Title, Form } from '@patternfly/react-core';
|
5
|
+
import { translate as __ } from 'foremanReact/common/I18n';
|
6
|
+
import { selectJobTemplate } from '../../JobWizardSelectors';
|
7
|
+
import {
|
8
|
+
EffectiveUserField,
|
9
|
+
TimeoutToKillField,
|
10
|
+
PasswordField,
|
11
|
+
KeyPassphraseField,
|
12
|
+
EffectiveUserPasswordField,
|
13
|
+
ConcurrencyLevelField,
|
14
|
+
TimeSpanLevelField,
|
15
|
+
} from './Fields';
|
16
|
+
|
17
|
+
export const AdvancedFields = ({ advancedValues, setAdvancedValues }) => {
|
18
|
+
const jobTemplate = useSelector(selectJobTemplate);
|
19
|
+
const effectiveUser = jobTemplate.effective_user;
|
20
|
+
return (
|
21
|
+
<>
|
22
|
+
<Title headingLevel="h2" className="advanced-fields-title">
|
23
|
+
{__('Advanced Fields')}
|
24
|
+
</Title>
|
25
|
+
<Form>
|
26
|
+
{effectiveUser?.overridable && (
|
27
|
+
<EffectiveUserField
|
28
|
+
value={advancedValues.effectiveUserValue}
|
29
|
+
setValue={newValue =>
|
30
|
+
setAdvancedValues({
|
31
|
+
effectiveUserValue: newValue,
|
32
|
+
})
|
33
|
+
}
|
34
|
+
/>
|
35
|
+
)}
|
36
|
+
<TimeoutToKillField
|
37
|
+
value={advancedValues.timeoutToKill}
|
38
|
+
setValue={newValue =>
|
39
|
+
setAdvancedValues({
|
40
|
+
timeoutToKill: newValue,
|
41
|
+
})
|
42
|
+
}
|
43
|
+
/>
|
44
|
+
<PasswordField
|
45
|
+
value={advancedValues.password}
|
46
|
+
setValue={newValue =>
|
47
|
+
setAdvancedValues({
|
48
|
+
password: newValue,
|
49
|
+
})
|
50
|
+
}
|
51
|
+
/>
|
52
|
+
<KeyPassphraseField
|
53
|
+
value={advancedValues.keyPassphrase}
|
54
|
+
setValue={newValue =>
|
55
|
+
setAdvancedValues({
|
56
|
+
keyPassphrase: newValue,
|
57
|
+
})
|
58
|
+
}
|
59
|
+
/>
|
60
|
+
<EffectiveUserPasswordField
|
61
|
+
value={advancedValues.effectiveUserPassword}
|
62
|
+
setValue={newValue =>
|
63
|
+
setAdvancedValues({
|
64
|
+
effectiveUserPassword: newValue,
|
65
|
+
})
|
66
|
+
}
|
67
|
+
/>
|
68
|
+
<ConcurrencyLevelField
|
69
|
+
value={advancedValues.concurrencyLevel}
|
70
|
+
setValue={newValue =>
|
71
|
+
setAdvancedValues({
|
72
|
+
concurrencyLevel: newValue,
|
73
|
+
})
|
74
|
+
}
|
75
|
+
/>
|
76
|
+
<TimeSpanLevelField
|
77
|
+
value={advancedValues.timeSpan}
|
78
|
+
setValue={newValue =>
|
79
|
+
setAdvancedValues({
|
80
|
+
timeSpan: newValue,
|
81
|
+
})
|
82
|
+
}
|
83
|
+
/>
|
84
|
+
</Form>
|
85
|
+
</>
|
86
|
+
);
|
87
|
+
};
|
88
|
+
|
89
|
+
AdvancedFields.propTypes = {
|
90
|
+
advancedValues: PropTypes.object.isRequired,
|
91
|
+
setAdvancedValues: PropTypes.func.isRequired,
|
92
|
+
};
|
93
|
+
export default AdvancedFields;
|
@@ -0,0 +1,181 @@
|
|
1
|
+
import React from 'react';
|
2
|
+
import PropTypes from 'prop-types';
|
3
|
+
import { FormGroup, TextInput } from '@patternfly/react-core';
|
4
|
+
import { translate as __ } from 'foremanReact/common/I18n';
|
5
|
+
import { helpLabel } from '../form/FormHelpers';
|
6
|
+
|
7
|
+
export const EffectiveUserField = ({ value, setValue }) => (
|
8
|
+
<FormGroup
|
9
|
+
label={__('Effective user')}
|
10
|
+
labelIcon={helpLabel(
|
11
|
+
__(
|
12
|
+
'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.'
|
13
|
+
),
|
14
|
+
'effective-user'
|
15
|
+
)}
|
16
|
+
fieldId="effective-user"
|
17
|
+
>
|
18
|
+
<TextInput
|
19
|
+
autoComplete="effective-user"
|
20
|
+
id="effective-user"
|
21
|
+
type="text"
|
22
|
+
value={value}
|
23
|
+
onChange={newValue => setValue(newValue)}
|
24
|
+
/>
|
25
|
+
</FormGroup>
|
26
|
+
);
|
27
|
+
|
28
|
+
export const TimeoutToKillField = ({ value, setValue }) => (
|
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.'
|
34
|
+
),
|
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>
|
48
|
+
);
|
49
|
+
|
50
|
+
export const PasswordField = ({ value, setValue }) => (
|
51
|
+
<FormGroup
|
52
|
+
label={__('Password')}
|
53
|
+
labelIcon={helpLabel(
|
54
|
+
__(
|
55
|
+
'Password is stored encrypted in DB until the job finishes. For future or recurring executions, it is removed after the last execution.'
|
56
|
+
),
|
57
|
+
'password'
|
58
|
+
)}
|
59
|
+
fieldId="password"
|
60
|
+
>
|
61
|
+
<TextInput
|
62
|
+
autoComplete="password"
|
63
|
+
id="password"
|
64
|
+
type="password"
|
65
|
+
placeholder="*****"
|
66
|
+
value={value}
|
67
|
+
onChange={newValue => setValue(newValue)}
|
68
|
+
/>
|
69
|
+
</FormGroup>
|
70
|
+
);
|
71
|
+
|
72
|
+
export const KeyPassphraseField = ({ value, setValue }) => (
|
73
|
+
<FormGroup
|
74
|
+
label={__('Private key passphrase')}
|
75
|
+
labelIcon={helpLabel(
|
76
|
+
__(
|
77
|
+
'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.'
|
78
|
+
),
|
79
|
+
'key-passphrase'
|
80
|
+
)}
|
81
|
+
fieldId="key-passphrase"
|
82
|
+
>
|
83
|
+
<TextInput
|
84
|
+
autoComplete="key-passphrase"
|
85
|
+
id="key-passphrase"
|
86
|
+
type="password"
|
87
|
+
placeholder="*****"
|
88
|
+
value={value}
|
89
|
+
onChange={newValue => setValue(newValue)}
|
90
|
+
/>
|
91
|
+
</FormGroup>
|
92
|
+
);
|
93
|
+
|
94
|
+
export const EffectiveUserPasswordField = ({ value, setValue }) => (
|
95
|
+
<FormGroup
|
96
|
+
label={__('Effective user password')}
|
97
|
+
labelIcon={helpLabel(
|
98
|
+
__(
|
99
|
+
'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.'
|
100
|
+
),
|
101
|
+
'effective-user-password'
|
102
|
+
)}
|
103
|
+
fieldId="effective-user-password"
|
104
|
+
>
|
105
|
+
<TextInput
|
106
|
+
autoComplete="effective-user-password"
|
107
|
+
id="effective-user-password"
|
108
|
+
type="password"
|
109
|
+
placeholder="*****"
|
110
|
+
value={value}
|
111
|
+
onChange={newValue => setValue(newValue)}
|
112
|
+
/>
|
113
|
+
</FormGroup>
|
114
|
+
);
|
115
|
+
|
116
|
+
export const ConcurrencyLevelField = ({ value, setValue }) => (
|
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.'
|
122
|
+
),
|
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>
|
137
|
+
);
|
138
|
+
|
139
|
+
export const TimeSpanLevelField = ({ value, setValue }) => (
|
140
|
+
<FormGroup
|
141
|
+
label={__('Time span')}
|
142
|
+
labelIcon={helpLabel(
|
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'
|
147
|
+
)}
|
148
|
+
fieldId="time-span"
|
149
|
+
>
|
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)}
|
158
|
+
/>
|
159
|
+
</FormGroup>
|
160
|
+
);
|
161
|
+
|
162
|
+
EffectiveUserField.propTypes = {
|
163
|
+
value: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),
|
164
|
+
setValue: PropTypes.func.isRequired,
|
165
|
+
};
|
166
|
+
EffectiveUserField.defaultProps = {
|
167
|
+
value: '',
|
168
|
+
};
|
169
|
+
|
170
|
+
TimeoutToKillField.propTypes = EffectiveUserField.propTypes;
|
171
|
+
TimeoutToKillField.defaultProps = EffectiveUserField.defaultProps;
|
172
|
+
PasswordField.propTypes = EffectiveUserField.propTypes;
|
173
|
+
PasswordField.defaultProps = EffectiveUserField.defaultProps;
|
174
|
+
KeyPassphraseField.propTypes = EffectiveUserField.propTypes;
|
175
|
+
KeyPassphraseField.defaultProps = EffectiveUserField.defaultProps;
|
176
|
+
EffectiveUserPasswordField.propTypes = EffectiveUserField.propTypes;
|
177
|
+
EffectiveUserPasswordField.defaultProps = EffectiveUserField.defaultProps;
|
178
|
+
ConcurrencyLevelField.propTypes = EffectiveUserField.propTypes;
|
179
|
+
ConcurrencyLevelField.defaultProps = EffectiveUserField.defaultProps;
|
180
|
+
TimeSpanLevelField.propTypes = EffectiveUserField.propTypes;
|
181
|
+
TimeSpanLevelField.defaultProps = EffectiveUserField.defaultProps;
|