foreman_remote_execution 8.2.0 → 8.2.1

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 (47) hide show
  1. checksums.yaml +4 -4
  2. data/app/controllers/api/v2/job_invocations_controller.rb +1 -0
  3. data/app/controllers/ui_job_wizard_controller.rb +6 -1
  4. data/app/views/api/v2/job_invocations/base.json.rabl +1 -1
  5. data/app/views/job_invocations/show.html.erb +1 -1
  6. data/app/views/job_invocations/welcome.html.erb +1 -1
  7. data/db/migrate/20210816100932_rex_setting_category_to_dsl.rb +1 -1
  8. data/lib/foreman_remote_execution/version.rb +1 -1
  9. data/locale/action_names.rb +2 -2
  10. data/locale/de/LC_MESSAGES/foreman_remote_execution.mo +0 -0
  11. data/locale/de/foreman_remote_execution.po +266 -154
  12. data/locale/en/LC_MESSAGES/foreman_remote_execution.mo +0 -0
  13. data/locale/en/foreman_remote_execution.po +132 -24
  14. data/locale/en_GB/LC_MESSAGES/foreman_remote_execution.mo +0 -0
  15. data/locale/en_GB/foreman_remote_execution.po +149 -41
  16. data/locale/es/LC_MESSAGES/foreman_remote_execution.mo +0 -0
  17. data/locale/es/foreman_remote_execution.po +320 -210
  18. data/locale/foreman_remote_execution.pot +394 -211
  19. data/locale/fr/LC_MESSAGES/foreman_remote_execution.mo +0 -0
  20. data/locale/fr/foreman_remote_execution.po +353 -241
  21. data/locale/ja/LC_MESSAGES/foreman_remote_execution.mo +0 -0
  22. data/locale/ja/foreman_remote_execution.po +368 -261
  23. data/locale/ko/LC_MESSAGES/foreman_remote_execution.mo +0 -0
  24. data/locale/ko/foreman_remote_execution.po +161 -53
  25. data/locale/pt_BR/LC_MESSAGES/foreman_remote_execution.mo +0 -0
  26. data/locale/pt_BR/foreman_remote_execution.po +335 -225
  27. data/locale/ru/LC_MESSAGES/foreman_remote_execution.mo +0 -0
  28. data/locale/ru/foreman_remote_execution.po +161 -53
  29. data/locale/zh_CN/LC_MESSAGES/foreman_remote_execution.mo +0 -0
  30. data/locale/zh_CN/foreman_remote_execution.po +465 -359
  31. data/locale/zh_TW/LC_MESSAGES/foreman_remote_execution.mo +0 -0
  32. data/locale/zh_TW/foreman_remote_execution.po +162 -54
  33. data/webpack/JobWizard/JobWizard.js +52 -10
  34. data/webpack/JobWizard/__tests__/__snapshots__/integration.test.js.snap +8 -0
  35. data/webpack/JobWizard/__tests__/fixtures.js +5 -0
  36. data/webpack/JobWizard/__tests__/integration.test.js +15 -0
  37. data/webpack/JobWizard/__tests__/validation.test.js +27 -0
  38. data/webpack/JobWizard/autofill.js +1 -0
  39. data/webpack/JobWizard/steps/AdvancedFields/__tests__/AdvancedFields.test.js +19 -0
  40. data/webpack/JobWizard/steps/AdvancedFields/__tests__/__snapshots__/AdvancedFields.test.js.snap +8 -0
  41. data/webpack/JobWizard/steps/HostsAndInputs/HostPreviewModal.js +3 -0
  42. data/webpack/JobWizard/steps/HostsAndInputs/__tests__/HostsAndInputs.test.js +31 -1
  43. data/webpack/JobWizard/steps/HostsAndInputs/buildHostQuery.js +16 -10
  44. data/webpack/JobWizard/steps/HostsAndInputs/index.js +51 -3
  45. data/webpack/JobWizard/steps/Schedule/__tests__/Schedule.test.js +21 -1
  46. data/webpack/JobWizard/submit.js +13 -2
  47. metadata +2 -2
@@ -209,6 +209,11 @@ export const JobWizard = ({ rerunData }) => {
209
209
  !templateError &&
210
210
  !!jobTemplateID &&
211
211
  templateResponse.job_template;
212
+ const areHostsSelected =
213
+ selectedTargets.hosts.length > 0 ||
214
+ selectedTargets.hostCollections.length > 0 ||
215
+ selectedTargets.hostGroups.length > 0 ||
216
+ hostsSearchQuery.length > 0;
212
217
  const steps = [
213
218
  {
214
219
  name: WIZARD_TITLES.categoryAndTemplate,
@@ -238,7 +243,7 @@ export const JobWizard = ({ rerunData }) => {
238
243
  />
239
244
  ),
240
245
  canJumpTo: isTemplate,
241
- enableNext: isTemplate && valid.hostsAndInputs,
246
+ enableNext: isTemplate && valid.hostsAndInputs && areHostsSelected,
242
247
  },
243
248
  {
244
249
  name: WIZARD_TITLES.advanced,
@@ -254,14 +259,26 @@ export const JobWizard = ({ rerunData }) => {
254
259
  templateValues={templateValues}
255
260
  />
256
261
  ),
257
- canJumpTo: isTemplate && valid.hostsAndInputs,
258
- enableNext: isTemplate && valid.hostsAndInputs && valid.advanced,
262
+ canJumpTo: isTemplate && valid.hostsAndInputs && areHostsSelected,
263
+ enableNext:
264
+ isTemplate &&
265
+ valid.hostsAndInputs &&
266
+ areHostsSelected &&
267
+ valid.advanced,
259
268
  },
260
269
  {
261
270
  name: WIZARD_TITLES.schedule,
262
- canJumpTo: isTemplate && valid.hostsAndInputs && valid.advanced,
271
+ canJumpTo:
272
+ isTemplate &&
273
+ valid.hostsAndInputs &&
274
+ areHostsSelected &&
275
+ valid.advanced,
263
276
  enableNext:
264
- isTemplate && valid.hostsAndInputs && valid.advanced && valid.schedule,
277
+ isTemplate &&
278
+ valid.hostsAndInputs &&
279
+ areHostsSelected &&
280
+ valid.advanced &&
281
+ valid.schedule,
265
282
  steps: [
266
283
  {
267
284
  name: WIZARD_TITLES.typeOfExecution,
@@ -278,9 +295,17 @@ export const JobWizard = ({ rerunData }) => {
278
295
  }}
279
296
  />
280
297
  ),
281
- canJumpTo: isTemplate && valid.hostsAndInputs && valid.advanced,
298
+ canJumpTo:
299
+ isTemplate &&
300
+ valid.hostsAndInputs &&
301
+ areHostsSelected &&
302
+ valid.advanced,
282
303
 
283
- enableNext: isTemplate && valid.hostsAndInputs && valid.advanced,
304
+ enableNext:
305
+ isTemplate &&
306
+ valid.hostsAndInputs &&
307
+ areHostsSelected &&
308
+ valid.advanced,
284
309
  },
285
310
  ...(scheduleValue.scheduleType === SCHEDULE_TYPES.FUTURE
286
311
  ? [
@@ -298,10 +323,15 @@ export const JobWizard = ({ rerunData }) => {
298
323
  }}
299
324
  />
300
325
  ),
301
- canJumpTo: isTemplate && valid.hostsAndInputs && valid.advanced,
326
+ canJumpTo:
327
+ isTemplate &&
328
+ valid.hostsAndInputs &&
329
+ areHostsSelected &&
330
+ valid.advanced,
302
331
  enableNext:
303
332
  isTemplate &&
304
333
  valid.hostsAndInputs &&
334
+ areHostsSelected &&
305
335
  valid.advanced &&
306
336
  valid.schedule,
307
337
  },
@@ -323,10 +353,15 @@ export const JobWizard = ({ rerunData }) => {
323
353
  }}
324
354
  />
325
355
  ),
326
- canJumpTo: isTemplate && valid.hostsAndInputs && valid.advanced,
356
+ canJumpTo:
357
+ isTemplate &&
358
+ valid.hostsAndInputs &&
359
+ areHostsSelected &&
360
+ valid.advanced,
327
361
  enableNext:
328
362
  isTemplate &&
329
363
  valid.hostsAndInputs &&
364
+ areHostsSelected &&
330
365
  valid.advanced &&
331
366
  valid.schedule,
332
367
  },
@@ -349,10 +384,15 @@ export const JobWizard = ({ rerunData }) => {
349
384
  ),
350
385
  nextButtonText: 'Run',
351
386
  canJumpTo:
352
- isTemplate && valid.hostsAndInputs && valid.advanced && valid.schedule,
387
+ isTemplate &&
388
+ valid.advanced &&
389
+ valid.hostsAndInputs &&
390
+ areHostsSelected &&
391
+ valid.schedule,
353
392
  enableNext:
354
393
  isTemplate &&
355
394
  valid.hostsAndInputs &&
395
+ areHostsSelected &&
356
396
  valid.advanced &&
357
397
  valid.schedule &&
358
398
  !isSubmitting,
@@ -379,6 +419,8 @@ export const JobWizard = ({ rerunData }) => {
379
419
  location,
380
420
  organization,
381
421
  feature: routerSearch?.feature,
422
+ provider: templateResponse.provider_name,
423
+ advancedInputs: templateResponse.advanced_template_inputs,
382
424
  });
383
425
  }}
384
426
  />
@@ -7,6 +7,14 @@ Array [
7
7
  "type": "get",
8
8
  "url": "/ui_job_wizard/categories",
9
9
  },
10
+ Object {
11
+ "key": "HOST_IDS",
12
+ "params": Object {
13
+ "search": "id = 105 or id = 37",
14
+ },
15
+ "type": "get",
16
+ "url": "/api/hosts",
17
+ },
10
18
  Object {
11
19
  "key": "JOB_TEMPLATES",
12
20
  "type": "get",
@@ -161,6 +161,11 @@ export const testSetup = (selectors, api) => {
161
161
  ],
162
162
  },
163
163
  },
164
+ HOSTS_API: {
165
+ response: {
166
+ subtotal: 3,
167
+ },
168
+ },
164
169
  });
165
170
  return store;
166
171
  };
@@ -18,6 +18,15 @@ import {
18
18
  const store = testSetup(selectors, api);
19
19
 
20
20
  describe('Job wizard fill', () => {
21
+ beforeEach(() => {
22
+ jest.spyOn(selectors, 'selectRouterSearch');
23
+ selectors.selectRouterSearch.mockImplementation(() => ({
24
+ 'host_ids[]': ['105', '37'],
25
+ }));
26
+ });
27
+ afterEach(() => {
28
+ selectors.selectRouterSearch.mockRestore();
29
+ });
21
30
  it('should select template', async () => {
22
31
  api.get.mockImplementation(({ handleSuccess, ...action }) => {
23
32
  if (action.key === 'JOB_CATEGORIES') {
@@ -33,7 +42,13 @@ describe('Job wizard fill', () => {
33
42
  handleSuccess({
34
43
  data: jobTemplate,
35
44
  });
45
+ } else if (action.key === 'HOST_IDS') {
46
+ handleSuccess &&
47
+ handleSuccess({
48
+ data: { results: [{ name: 'host1' }, { name: 'host3' }] },
49
+ });
36
50
  }
51
+
37
52
  return { type: 'get', ...action };
38
53
  });
39
54
  selectors.selectJobTemplate.mockRestore();
@@ -41,11 +41,26 @@ describe('Job wizard validation', () => {
41
41
  expect(screen.getByText(WIZARD_TITLES.review)).toBeDisabled();
42
42
  await act(async () => {
43
43
  fireEvent.click(screen.getByText(WIZARD_TITLES.hostsAndInputs));
44
+ await new Promise(resolve => setTimeout(resolve, 0)); // to resolve gql
44
45
  });
46
+ const select = name =>
47
+ screen.getByRole('button', { name: `${name} toggle` });
48
+ fireEvent.click(select('hosts'));
49
+ await act(async () => {
50
+ fireEvent.click(screen.getByText('host1'));
51
+ });
52
+
53
+ expect(screen.getByText(WIZARD_TITLES.advanced)).toBeDisabled();
54
+ expect(screen.getByText(WIZARD_TITLES.schedule)).toBeDisabled();
55
+ expect(screen.getByText(WIZARD_TITLES.review)).toBeDisabled();
45
56
  const textField = screen.getByLabelText('plain hidden', {
46
57
  selector: 'textarea',
47
58
  });
48
59
  await act(async () => {
60
+ fireEvent.click(
61
+ // Close the select
62
+ select('hosts')
63
+ );
49
64
  await fireEvent.change(textField, {
50
65
  target: { value: 'text' },
51
66
  });
@@ -85,8 +100,20 @@ describe('Job wizard validation', () => {
85
100
  // setup
86
101
  await act(async () => {
87
102
  fireEvent.click(screen.getByText(WIZARD_TITLES.hostsAndInputs));
103
+ await new Promise(resolve => setTimeout(resolve, 0)); // to resolve gql
88
104
  });
105
+
106
+ const select = name =>
107
+ screen.getByRole('button', { name: `${name} toggle` });
108
+ fireEvent.click(select('hosts'));
89
109
  await act(async () => {
110
+ fireEvent.click(screen.getByText('host1'));
111
+ });
112
+ await act(async () => {
113
+ fireEvent.click(
114
+ // Close the host select
115
+ select('hosts')
116
+ );
90
117
  await fireEvent.change(
91
118
  screen.getByLabelText('plain hidden', {
92
119
  selector: 'textarea',
@@ -72,6 +72,7 @@ export const useAutoFill = ({
72
72
  if (input) {
73
73
  if (typeof rest[key] === 'string') {
74
74
  setTemplateValues(prev => ({ ...prev, [input]: rest[key] }));
75
+ setAdvancedValues(prev => ({ ...prev, [input]: rest[key] }));
75
76
  } else {
76
77
  const { value, advanced } = rest[key];
77
78
  if (advanced) {
@@ -26,6 +26,15 @@ mockApi(api);
26
26
  jest.useFakeTimers();
27
27
 
28
28
  describe('AdvancedFields', () => {
29
+ beforeEach(() => {
30
+ jest.spyOn(selectors, 'selectRouterSearch');
31
+ selectors.selectRouterSearch.mockImplementation(() => ({
32
+ 'host_ids[]': ['105', '37'],
33
+ }));
34
+ });
35
+ afterEach(() => {
36
+ selectors.selectRouterSearch.mockRestore();
37
+ });
29
38
  it('should save data between steps for advanced fields', async () => {
30
39
  const wrapper = mount(
31
40
  <MockedProvider mocks={gqlMock} addTypename={false}>
@@ -270,6 +279,11 @@ describe('AdvancedFields', () => {
270
279
  handleSuccess({
271
280
  data: { results: [jobTemplate] },
272
281
  });
282
+ } else if (action.key === 'HOST_IDS') {
283
+ handleSuccess &&
284
+ handleSuccess({
285
+ data: { results: [{ name: 'host1' }, { name: 'host3' }] },
286
+ });
273
287
  }
274
288
  return { type: 'get', ...action };
275
289
  });
@@ -339,6 +353,11 @@ describe('AdvancedFields', () => {
339
353
  handleSuccess({
340
354
  data: { results: [jobTemplate] },
341
355
  });
356
+ } else if (action.key === 'HOST_IDS') {
357
+ handleSuccess &&
358
+ handleSuccess({
359
+ data: { results: [{ name: 'host1' }, { name: 'host3' }] },
360
+ });
342
361
  }
343
362
  return { type: 'get', ...action };
344
363
  });
@@ -7,6 +7,14 @@ Array [
7
7
  "type": "get",
8
8
  "url": "/ui_job_wizard/categories",
9
9
  },
10
+ Object {
11
+ "key": "HOST_IDS",
12
+ "params": Object {
13
+ "search": "id = 105 or id = 37",
14
+ },
15
+ "type": "get",
16
+ "url": "/api/hosts",
17
+ },
10
18
  Object {
11
19
  "key": "JOB_TEMPLATES",
12
20
  "type": "get",
@@ -60,3 +60,6 @@ HostPreviewModal.propTypes = {
60
60
  setIsOpen: PropTypes.func.isRequired,
61
61
  searchQuery: PropTypes.string.isRequired,
62
62
  };
63
+ HostPreviewModal.defaultPropTypes = {
64
+ searchQuery: '',
65
+ };
@@ -30,6 +30,27 @@ describe('Hosts', () => {
30
30
  const select = name =>
31
31
  screen.getByRole('button', { name: `${name} toggle` });
32
32
  fireEvent.click(select('hosts'));
33
+ await act(async () => {
34
+ fireEvent.click(screen.getByText('host1'));
35
+ fireEvent.click(select('hosts'));
36
+ });
37
+ expect(
38
+ screen.queryAllByText('Please select at least one host')
39
+ ).toHaveLength(0);
40
+ await act(async () => {
41
+ fireEvent.click(select('hosts'));
42
+ });
43
+ await act(async () => {
44
+ fireEvent.click(
45
+ screen.getByText('host1', {
46
+ selector: '.pf-c-select__menu-item',
47
+ })
48
+ );
49
+ fireEvent.blur(select('hosts'));
50
+ });
51
+ expect(
52
+ screen.queryAllByText('Please select at least one host')
53
+ ).toHaveLength(1);
33
54
  await act(async () => {
34
55
  fireEvent.click(screen.getByText('host1'));
35
56
  fireEvent.click(screen.getByText('host2'));
@@ -151,8 +172,9 @@ describe('Hosts', () => {
151
172
 
152
173
  it('input fill from url', async () => {
153
174
  const inputText = 'test text';
175
+ const advancedInputText = 'test adv text';
154
176
  routerSelectors.selectRouterLocation.mockImplementation(() => ({
155
- search: `feature=test_feature&inputs[plain hidden]=${inputText}`,
177
+ search: `host_ids%5B%5D=host1&host_ids%5B%5D=host3&feature=test_feature&inputs[plain hidden]=${inputText}&inputs[adv plain hidden]=${advancedInputText}`,
156
178
  }));
157
179
  render(
158
180
  <MockedProvider mocks={gqlMock} addTypename={false}>
@@ -175,5 +197,13 @@ describe('Hosts', () => {
175
197
  selector: 'textarea',
176
198
  });
177
199
  expect(textField.value).toBe(inputText);
200
+
201
+ await act(async () => {
202
+ fireEvent.click(screen.getByText('Advanced fields'));
203
+ });
204
+ const advancedTextField = screen.getByLabelText('adv plain hidden', {
205
+ selector: 'textarea',
206
+ });
207
+ expect(advancedTextField.value).toBe(advancedInputText);
178
208
  });
179
209
  });
@@ -1,18 +1,24 @@
1
1
  export const buildHostQuery = (selected, search) => {
2
2
  const { hosts, hostCollections, hostGroups } = selected;
3
- const hostsSearch = `(id ^ (${hosts.map(({ id }) => id).join(',')}))`;
4
- const hostCollectionsSearch = `(host_collection_id ^ (${hostCollections
3
+ const hostsSearch = `id ^ (${hosts.map(({ id }) => id).join(',')})`;
4
+ const hostCollectionsSearch = `host_collection_id ^ (${hostCollections
5
5
  .map(({ id }) => id)
6
- .join(',')}))`;
7
- const hostGroupsSearch = `(hostgroup_id ^ (${hostGroups
6
+ .join(',')})`;
7
+ const hostGroupsSearch = `hostgroup_id ^ (${hostGroups
8
8
  .map(({ id }) => id)
9
- .join(',')}))`;
10
- return [
9
+ .join(',')})`;
10
+ const queryParts = [
11
11
  hosts.length ? hostsSearch : false,
12
12
  hostCollections.length ? hostCollectionsSearch : false,
13
13
  hostGroups.length ? hostGroupsSearch : false,
14
- search.length ? `(${search})` : false,
15
- ]
16
- .filter(Boolean)
17
- .join(' or ');
14
+ search.length ? search : false,
15
+ ].filter(Boolean);
16
+
17
+ if (queryParts.length === 0) {
18
+ return 'name=a AND name=b';
19
+ }
20
+ if (queryParts.length === 1) {
21
+ return queryParts[0] || 'name=a AND name=b';
22
+ }
23
+ return queryParts.map(p => `(${p})`).join(' or ') || 'name=a AND name=b';
18
24
  };
@@ -54,6 +54,30 @@ const HostsAndInputs = ({
54
54
  const isLoading = useSelector(selectIsLoadingHosts);
55
55
  const templateInputs = useSelector(selectTemplateInputs);
56
56
  const [hostPreviewOpen, setHostPreviewOpen] = useState(false);
57
+ const [wasFocus, setWasFocus] = useState(false);
58
+ const [isError, setIsError] = useState(false);
59
+ useEffect(() => {
60
+ if (wasFocus) {
61
+ if (
62
+ selected.hosts.length === 0 &&
63
+ selected.hostCollections.length === 0 &&
64
+ selected.hostGroups.length === 0 &&
65
+ hostsSearchQuery.length === 0
66
+ ) {
67
+ setIsError(true);
68
+ } else {
69
+ setIsError(false);
70
+ }
71
+ }
72
+ }, [
73
+ hostMethod,
74
+ hostsSearchQuery.length,
75
+ selected,
76
+ selected.hostCollections.length,
77
+ selected.hostGroups.length,
78
+ selected.hosts.length,
79
+ wasFocus,
80
+ ]);
57
81
  useEffect(() => {
58
82
  debounce(() => {
59
83
  dispatch(
@@ -103,6 +127,9 @@ const HostsAndInputs = ({
103
127
  dispatch(resetData(hostsController, hostQuerySearchID));
104
128
  setHostsSearchQuery('');
105
129
  };
130
+ const [errorText, setErrorText] = useState(
131
+ __('Please select at least one host')
132
+ );
106
133
  return (
107
134
  <div className="target-hosts-and-inputs">
108
135
  <WizardTitle title={WIZARD_TITLES.hostsAndInputs} />
@@ -114,8 +141,13 @@ const HostsAndInputs = ({
114
141
  />
115
142
  )}
116
143
  <Form>
117
- <FormGroup fieldId="host_selection" id="host-selection">
118
- <InputGroup>
144
+ <FormGroup
145
+ fieldId="host_selection"
146
+ id="host-selection"
147
+ helperTextInvalid={errorText}
148
+ validated={isError ? 'error' : 'default'}
149
+ >
150
+ <InputGroup onBlur={() => setWasFocus(true)}>
119
151
  <SelectField
120
152
  isRequired
121
153
  className="target-method-select"
@@ -127,7 +159,23 @@ const HostsAndInputs = ({
127
159
  }
128
160
  return true;
129
161
  })}
130
- setValue={setHostMethod}
162
+ setValue={val => {
163
+ setHostMethod(val);
164
+ if (val === hostMethods.searchQuery) {
165
+ setErrorText(__('Please enter a search query'));
166
+ }
167
+ if (val === hostMethods.hosts) {
168
+ setErrorText(__('Please select at least one host'));
169
+ }
170
+ if (val === hostMethods.hostCollections) {
171
+ setErrorText(
172
+ __('Please select at least one host collection')
173
+ );
174
+ }
175
+ if (val === hostMethods.hostGroups) {
176
+ setErrorText(__('Please select at least one host group'));
177
+ }
178
+ }}
131
179
  value={hostMethod}
132
180
  />
133
181
  {hostMethod === hostMethods.searchQuery && (
@@ -39,15 +39,35 @@ api.get.mockImplementation(({ handleSuccess, ...action }) => {
39
39
  handleSuccess({
40
40
  data: { results: [jobTemplateResponse.job_template] },
41
41
  });
42
+ } else if (action.key === 'HOST_IDS') {
43
+ handleSuccess &&
44
+ handleSuccess({
45
+ data: { results: [{ name: 'host1' }, { name: 'host3' }] },
46
+ });
42
47
  }
43
48
  return { type: 'get', ...action };
44
49
  });
45
50
 
46
51
  const mockStore = configureMockStore([]);
47
- const store = mockStore({});
52
+ const store = mockStore({
53
+ HOSTS_API: {
54
+ response: {
55
+ subtotal: 3,
56
+ },
57
+ },
58
+ });
48
59
  jest.useFakeTimers();
49
60
 
50
61
  describe('Schedule', () => {
62
+ beforeEach(() => {
63
+ jest.spyOn(selectors, 'selectRouterSearch');
64
+ selectors.selectRouterSearch.mockImplementation(() => ({
65
+ 'host_ids[]': ['105', '37'],
66
+ }));
67
+ });
68
+ afterEach(() => {
69
+ selectors.selectRouterSearch.mockRestore();
70
+ });
51
71
  it('sub steps appear', () => {
52
72
  render(
53
73
  <Provider store={store}>
@@ -12,6 +12,8 @@ export const submit = ({
12
12
  location,
13
13
  organization,
14
14
  feature,
15
+ provider,
16
+ advancedInputs,
15
17
  dispatch,
16
18
  }) => {
17
19
  const {
@@ -37,6 +39,13 @@ export const submit = ({
37
39
  keyPassphrase,
38
40
  timeToPickup,
39
41
  } = advancedValues;
42
+ const providerInputs = advancedInputs.filter(v => v.provider_input);
43
+ const providerValues = {};
44
+ providerInputs.forEach(({ name }) => {
45
+ providerValues[name] = advancedTemplateValues[name];
46
+ delete advancedTemplateValues[name];
47
+ });
48
+
40
49
  const getCronLine = () => {
41
50
  const [hour, minute] = repeatData.at
42
51
  ? repeatData.at.split(':')
@@ -104,14 +113,16 @@ export const submit = ({
104
113
  concurrency_level: concurrencyLevel,
105
114
  },
106
115
  bookmark_id: null,
107
- search_query:
108
- buildHostQuery(selectedTargets, hostsSearchQuery) || 'name ~ *',
116
+ search_query: buildHostQuery(selectedTargets, hostsSearchQuery),
109
117
  description_format: description,
110
118
  execution_timeout_interval: timeoutToKill,
111
119
  feature,
112
120
  time_to_pickup: timeToPickup,
113
121
  },
114
122
  };
123
+ if (Object.keys(providerValues).length) {
124
+ api.job_invocation[provider] = providerValues;
125
+ }
115
126
 
116
127
  dispatch(
117
128
  post({
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: foreman_remote_execution
3
3
  version: !ruby/object:Gem::Version
4
- version: 8.2.0
4
+ version: 8.2.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Foreman Remote Execution team
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2023-01-18 00:00:00.000000000 Z
11
+ date: 2023-02-21 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: deface