foreman_remote_execution 4.4.0 → 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/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
@@ -0,0 +1,25 @@
|
|
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 } from '@theforeman/test';
|
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
|
+
});
|
16
|
+
describe('AdvancedFields', () => {
|
17
|
+
it('rendring', () => {
|
18
|
+
const component = mount(
|
19
|
+
<Provider store={store}>
|
20
|
+
<AdvancedFields advancedValues={{}} setAdvancedValues={jest.fn()} />
|
21
|
+
</Provider>
|
22
|
+
);
|
23
|
+
expect(component).toMatchSnapshot();
|
24
|
+
});
|
25
|
+
});
|
data/webpack/JobWizard/steps/AdvancedFields/__tests__/__snapshots__/AdvancedFields.test.js.snap
ADDED
@@ -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,6 +1,6 @@
|
|
1
1
|
import React from 'react';
|
2
2
|
import PropTypes from 'prop-types';
|
3
|
-
import { Title, Text, TextVariants, Form } 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';
|
@@ -12,6 +12,7 @@ export const CategoryAndTemplate = ({
|
|
12
12
|
selectedTemplateID,
|
13
13
|
selectedCategory,
|
14
14
|
setCategory,
|
15
|
+
errors,
|
15
16
|
}) => {
|
16
17
|
const templatesGroups = {};
|
17
18
|
jobTemplates.forEach(template => {
|
@@ -35,9 +36,11 @@ export const CategoryAndTemplate = ({
|
|
35
36
|
setCategory(newCategory);
|
36
37
|
setJobTemplate(null);
|
37
38
|
};
|
39
|
+
const { categoryError, allTemplatesError, templateError } = errors;
|
40
|
+
const isError = !!(categoryError || allTemplatesError || templateError);
|
38
41
|
return (
|
39
42
|
<>
|
40
|
-
<Title headingLevel="h2">{__('Category
|
43
|
+
<Title headingLevel="h2">{__('Category and Template')}</Title>
|
41
44
|
<Text component={TextVariants.p}>{__('All fields are required.')}</Text>
|
42
45
|
<Form>
|
43
46
|
<SelectField
|
@@ -46,6 +49,8 @@ export const CategoryAndTemplate = ({
|
|
46
49
|
options={jobCategories}
|
47
50
|
setValue={onSelectCategory}
|
48
51
|
value={selectedCategory}
|
52
|
+
placeholderText={categoryError ? __('Error') : ''}
|
53
|
+
isDisabled={!!categoryError}
|
49
54
|
/>
|
50
55
|
<GroupedSelectField
|
51
56
|
label={__('Job template')}
|
@@ -53,7 +58,28 @@ export const CategoryAndTemplate = ({
|
|
53
58
|
groups={Object.values(templatesGroups)}
|
54
59
|
setSelected={setJobTemplate}
|
55
60
|
selected={selectedTemplate}
|
61
|
+
isDisabled={!!(categoryError || allTemplatesError)}
|
62
|
+
placeholderText={allTemplatesError ? __('Error') : ''}
|
56
63
|
/>
|
64
|
+
{isError && (
|
65
|
+
<Alert variant="danger" title={__('Errors:')}>
|
66
|
+
{categoryError && (
|
67
|
+
<span>
|
68
|
+
{__('Categories list failed with:')} {categoryError}
|
69
|
+
</span>
|
70
|
+
)}
|
71
|
+
{allTemplatesError && (
|
72
|
+
<span>
|
73
|
+
{__('Templates list failed with:')} {allTemplatesError}
|
74
|
+
</span>
|
75
|
+
)}
|
76
|
+
{templateError && (
|
77
|
+
<span>
|
78
|
+
{__('Template failed with:')} {templateError}
|
79
|
+
</span>
|
80
|
+
)}
|
81
|
+
</Alert>
|
82
|
+
)}
|
57
83
|
</Form>
|
58
84
|
</>
|
59
85
|
);
|
@@ -66,12 +92,18 @@ CategoryAndTemplate.propTypes = {
|
|
66
92
|
selectedTemplateID: PropTypes.number,
|
67
93
|
setCategory: PropTypes.func.isRequired,
|
68
94
|
selectedCategory: PropTypes.string,
|
95
|
+
errors: PropTypes.shape({
|
96
|
+
categoryError: PropTypes.string,
|
97
|
+
allTemplatesError: PropTypes.string,
|
98
|
+
templateError: PropTypes.string,
|
99
|
+
}),
|
69
100
|
};
|
70
101
|
CategoryAndTemplate.defaultProps = {
|
71
102
|
jobCategories: [],
|
72
103
|
jobTemplates: [],
|
73
104
|
selectedTemplateID: null,
|
74
105
|
selectedCategory: null,
|
106
|
+
errors: {},
|
75
107
|
};
|
76
108
|
|
77
109
|
export default CategoryAndTemplate;
|
@@ -1,8 +1,14 @@
|
|
1
1
|
import { testComponentSnapshotsWithFixtures } from '@theforeman/test';
|
2
2
|
import { CategoryAndTemplate } from './CategoryAndTemplate';
|
3
3
|
|
4
|
+
const baseProps = {
|
5
|
+
setJobTemplate: jest.fn(),
|
6
|
+
selectedTemplateID: 190,
|
7
|
+
setCategory: jest.fn(),
|
8
|
+
};
|
4
9
|
const fixtures = {
|
5
10
|
'renders with props': {
|
11
|
+
...baseProps,
|
6
12
|
jobCategories: [
|
7
13
|
'Commands',
|
8
14
|
'Ansible Playbook',
|
@@ -32,11 +38,12 @@ const fixtures = {
|
|
32
38
|
snippet: false,
|
33
39
|
},
|
34
40
|
],
|
35
|
-
setJobTemplate: jest.fn(),
|
36
|
-
selectedTemplateID: 190,
|
37
|
-
setCategory: jest.fn(),
|
38
41
|
selectedCategory: 'I am a category',
|
39
42
|
},
|
43
|
+
'render with error': {
|
44
|
+
...baseProps,
|
45
|
+
errors: { allTemplatesError: 'I have an error' },
|
46
|
+
},
|
40
47
|
};
|
41
48
|
|
42
49
|
describe('CategoryAndTemplate', () => {
|
data/webpack/JobWizard/steps/CategoryAndTemplate/__snapshots__/CategoryAndTemplate.test.js.snap
CHANGED
@@ -1,11 +1,56 @@
|
|
1
1
|
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
2
2
|
|
3
|
+
exports[`CategoryAndTemplate rendering render with error 1`] = `
|
4
|
+
<Fragment>
|
5
|
+
<Title
|
6
|
+
headingLevel="h2"
|
7
|
+
>
|
8
|
+
Category and Template
|
9
|
+
</Title>
|
10
|
+
<Text
|
11
|
+
component="p"
|
12
|
+
>
|
13
|
+
All fields are required.
|
14
|
+
</Text>
|
15
|
+
<Form>
|
16
|
+
<SelectField
|
17
|
+
fieldId="job_category"
|
18
|
+
isDisabled={false}
|
19
|
+
label="Job category"
|
20
|
+
options={Array []}
|
21
|
+
placeholderText=""
|
22
|
+
setValue={[Function]}
|
23
|
+
value={null}
|
24
|
+
/>
|
25
|
+
<GroupedSelectField
|
26
|
+
fieldId="job_template"
|
27
|
+
groups={Array []}
|
28
|
+
isDisabled={true}
|
29
|
+
label="Job template"
|
30
|
+
placeholderText="Error"
|
31
|
+
selected={null}
|
32
|
+
setSelected={[MockFunction]}
|
33
|
+
/>
|
34
|
+
<Alert
|
35
|
+
title="Errors:"
|
36
|
+
variant="danger"
|
37
|
+
>
|
38
|
+
<span>
|
39
|
+
Templates list failed with:
|
40
|
+
|
41
|
+
I have an error
|
42
|
+
</span>
|
43
|
+
</Alert>
|
44
|
+
</Form>
|
45
|
+
</Fragment>
|
46
|
+
`;
|
47
|
+
|
3
48
|
exports[`CategoryAndTemplate rendering renders with props 1`] = `
|
4
49
|
<Fragment>
|
5
50
|
<Title
|
6
51
|
headingLevel="h2"
|
7
52
|
>
|
8
|
-
Category
|
53
|
+
Category and Template
|
9
54
|
</Title>
|
10
55
|
<Text
|
11
56
|
component="p"
|
@@ -15,6 +60,7 @@ exports[`CategoryAndTemplate rendering renders with props 1`] = `
|
|
15
60
|
<Form>
|
16
61
|
<SelectField
|
17
62
|
fieldId="job_category"
|
63
|
+
isDisabled={false}
|
18
64
|
label="Job category"
|
19
65
|
options={
|
20
66
|
Array [
|
@@ -24,6 +70,7 @@ exports[`CategoryAndTemplate rendering renders with props 1`] = `
|
|
24
70
|
"Ansible Roles Installation",
|
25
71
|
]
|
26
72
|
}
|
73
|
+
placeholderText=""
|
27
74
|
setValue={[Function]}
|
28
75
|
value="I am a category"
|
29
76
|
/>
|
@@ -55,7 +102,9 @@ exports[`CategoryAndTemplate rendering renders with props 1`] = `
|
|
55
102
|
},
|
56
103
|
]
|
57
104
|
}
|
105
|
+
isDisabled={false}
|
58
106
|
label="Job template"
|
107
|
+
placeholderText=""
|
59
108
|
selected="ab Run Command - SSH Default clone"
|
60
109
|
setSelected={[MockFunction]}
|
61
110
|
/>
|