foreman_remote_execution 9.0.1 → 10.0.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.
- checksums.yaml +4 -4
- data/.github/workflows/release.yml +14 -0
- data/.tx/config +3 -1
- data/app/assets/javascripts/foreman_remote_execution/locale/de/foreman_remote_execution.js +1 -0
- data/app/assets/javascripts/foreman_remote_execution/locale/en/foreman_remote_execution.js +1 -0
- data/app/assets/javascripts/foreman_remote_execution/locale/en_GB/foreman_remote_execution.js +1 -0
- data/app/assets/javascripts/foreman_remote_execution/locale/es/foreman_remote_execution.js +1 -0
- data/app/assets/javascripts/foreman_remote_execution/locale/fr/foreman_remote_execution.js +1 -0
- data/app/assets/javascripts/foreman_remote_execution/locale/ja/foreman_remote_execution.js +1 -0
- data/app/assets/javascripts/foreman_remote_execution/locale/ko/foreman_remote_execution.js +1 -0
- data/app/assets/javascripts/foreman_remote_execution/locale/pt_BR/foreman_remote_execution.js +1 -0
- data/app/assets/javascripts/foreman_remote_execution/locale/ru/foreman_remote_execution.js +1 -0
- data/app/assets/javascripts/foreman_remote_execution/locale/zh_CN/foreman_remote_execution.js +1 -0
- data/app/assets/javascripts/foreman_remote_execution/locale/zh_TW/foreman_remote_execution.js +1 -0
- data/app/assets/javascripts/foreman_remote_execution/template_invocation.js +10 -1
- data/app/controllers/api/v2/job_invocations_controller.rb +1 -0
- data/app/controllers/job_invocations_controller.rb +30 -1
- data/app/controllers/ui_job_wizard_controller.rb +3 -1
- data/app/helpers/remote_execution_helper.rb +1 -1
- data/app/lib/actions/remote_execution/run_host_job.rb +1 -1
- data/app/lib/actions/remote_execution/run_hosts_job.rb +28 -2
- data/app/models/remote_execution_feature.rb +11 -8
- data/app/views/api/v2/job_invocations/base.json.rabl +1 -1
- data/app/views/job_invocations/_form.html.erb +1 -1
- data/app/views/job_invocations/show.html.erb +1 -1
- data/app/views/job_invocations/welcome.html.erb +1 -1
- data/app/views/templates/script/run_command.erb +1 -0
- data/config/routes.rb +2 -0
- data/db/migrate/20210816100932_rex_setting_category_to_dsl.rb +1 -1
- data/db/migrate/20220426145007_add_unique_feature_label_index.rb +14 -0
- data/lib/foreman_remote_execution/engine.rb +9 -9
- data/lib/foreman_remote_execution/tasks/explain_proxy_selection.rake +12 -3
- data/lib/foreman_remote_execution/version.rb +1 -1
- data/locale/Makefile +6 -3
- data/locale/action_names.rb +1 -1
- data/locale/de/LC_MESSAGES/foreman_remote_execution.mo +0 -0
- data/locale/de/foreman_remote_execution.po +67 -19
- data/locale/en/LC_MESSAGES/foreman_remote_execution.mo +0 -0
- data/locale/en/foreman_remote_execution.po +56 -8
- data/locale/en_GB/LC_MESSAGES/foreman_remote_execution.mo +0 -0
- data/locale/en_GB/foreman_remote_execution.po +58 -10
- data/locale/es/LC_MESSAGES/foreman_remote_execution.mo +0 -0
- data/locale/es/foreman_remote_execution.po +71 -23
- data/locale/foreman_remote_execution.pot +216 -141
- data/locale/fr/LC_MESSAGES/foreman_remote_execution.mo +0 -0
- data/locale/fr/foreman_remote_execution.po +104 -56
- data/locale/ja/LC_MESSAGES/foreman_remote_execution.mo +0 -0
- data/locale/ja/foreman_remote_execution.po +72 -24
- data/locale/ko/LC_MESSAGES/foreman_remote_execution.mo +0 -0
- data/locale/ko/foreman_remote_execution.po +63 -15
- data/locale/pt_BR/LC_MESSAGES/foreman_remote_execution.mo +0 -0
- data/locale/pt_BR/foreman_remote_execution.po +68 -20
- data/locale/ru/LC_MESSAGES/foreman_remote_execution.mo +0 -0
- data/locale/ru/foreman_remote_execution.po +63 -15
- data/locale/zh_CN/LC_MESSAGES/foreman_remote_execution.mo +0 -0
- data/locale/zh_CN/foreman_remote_execution.po +71 -23
- data/locale/zh_TW/LC_MESSAGES/foreman_remote_execution.mo +0 -0
- data/locale/zh_TW/foreman_remote_execution.po +63 -15
- data/package.json +6 -6
- data/webpack/JobWizard/Footer.js +104 -0
- data/webpack/JobWizard/JobWizard.js +105 -32
- data/webpack/JobWizard/JobWizard.scss +6 -17
- data/webpack/JobWizard/JobWizardConstants.js +1 -1
- data/webpack/JobWizard/JobWizardPageRerun.js +2 -0
- data/webpack/JobWizard/StartsBeforeErrorAlert.js +17 -0
- data/webpack/JobWizard/__tests__/__snapshots__/integration.test.js.snap +8 -0
- data/webpack/JobWizard/__tests__/fixtures.js +13 -1
- data/webpack/JobWizard/__tests__/integration.test.js +15 -0
- data/webpack/JobWizard/__tests__/validation.test.js +36 -0
- data/webpack/JobWizard/autofill.js +1 -0
- data/webpack/JobWizard/steps/AdvancedFields/__tests__/AdvancedFields.test.js +29 -10
- data/webpack/JobWizard/steps/AdvancedFields/__tests__/__snapshots__/AdvancedFields.test.js.snap +8 -0
- data/webpack/JobWizard/steps/HostsAndInputs/HostPreviewModal.js +5 -0
- data/webpack/JobWizard/steps/HostsAndInputs/SelectedChips.js +28 -14
- data/webpack/JobWizard/steps/HostsAndInputs/__tests__/HostsAndInputs.test.js +41 -4
- data/webpack/JobWizard/steps/HostsAndInputs/buildHostQuery.js +16 -10
- data/webpack/JobWizard/steps/HostsAndInputs/index.js +51 -3
- data/webpack/JobWizard/steps/ReviewDetails/ReviewDetails.test.js +117 -0
- data/webpack/JobWizard/steps/ReviewDetails/helpers.js +43 -0
- data/webpack/JobWizard/steps/ReviewDetails/index.js +169 -18
- data/webpack/JobWizard/steps/Schedule/QueryType.js +1 -1
- data/webpack/JobWizard/steps/Schedule/RepeatHour.js +0 -1
- data/webpack/JobWizard/steps/Schedule/RepeatWeek.js +1 -1
- data/webpack/JobWizard/steps/Schedule/__tests__/Schedule.test.js +52 -18
- data/webpack/JobWizard/steps/form/DateTimePicker.js +1 -2
- data/webpack/JobWizard/steps/form/GroupedSelectField.js +0 -1
- data/webpack/JobWizard/steps/form/SelectField.js +0 -1
- data/webpack/JobWizard/submit.js +14 -3
- data/webpack/react_app/components/RecentJobsCard/RecentJobsCard.js +4 -4
- data/webpack/react_app/components/RecentJobsCard/RecentJobsTable.js +2 -2
- data/webpack/react_app/components/RecentJobsCard/constants.js +2 -2
- data/webpack/react_app/components/RegistrationExtension/RexPull.js +0 -2
- metadata +23 -6
@@ -36,6 +36,8 @@ import { useValidation } from './validation';
|
|
36
36
|
import { useAutoFill } from './autofill';
|
37
37
|
import { submit } from './submit';
|
38
38
|
import { generateDefaultDescription } from './JobWizardHelpers';
|
39
|
+
import { StartsBeforeErrorAlert } from './StartsBeforeErrorAlert';
|
40
|
+
import { Footer } from './Footer';
|
39
41
|
import './JobWizard.scss';
|
40
42
|
|
41
43
|
export const JobWizard = ({ rerunData }) => {
|
@@ -185,6 +187,24 @@ export const JobWizard = ({ rerunData }) => {
|
|
185
187
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
186
188
|
}, [rerunData, jobTemplateID, dispatch]);
|
187
189
|
|
190
|
+
const [isStartsBeforeError, setIsStartsBeforeError] = useState(false);
|
191
|
+
useEffect(() => {
|
192
|
+
const updateStartsBeforeError = () => {
|
193
|
+
setIsStartsBeforeError(
|
194
|
+
scheduleValue.scheduleType === SCHEDULE_TYPES.FUTURE &&
|
195
|
+
new Date().getTime() >= new Date(scheduleValue.startsBefore).getTime()
|
196
|
+
);
|
197
|
+
};
|
198
|
+
let interval;
|
199
|
+
if (scheduleValue.scheduleType === SCHEDULE_TYPES.FUTURE) {
|
200
|
+
updateStartsBeforeError();
|
201
|
+
interval = setInterval(updateStartsBeforeError, 5000);
|
202
|
+
}
|
203
|
+
return () => {
|
204
|
+
interval && clearInterval(interval);
|
205
|
+
};
|
206
|
+
}, [scheduleValue.scheduleType, scheduleValue.startsBefore]);
|
207
|
+
|
188
208
|
const [valid, setValid] = useValidation({
|
189
209
|
advancedValues,
|
190
210
|
templateValues,
|
@@ -209,6 +229,11 @@ export const JobWizard = ({ rerunData }) => {
|
|
209
229
|
!templateError &&
|
210
230
|
!!jobTemplateID &&
|
211
231
|
templateResponse.job_template;
|
232
|
+
const areHostsSelected =
|
233
|
+
selectedTargets.hosts.length > 0 ||
|
234
|
+
selectedTargets.hostCollections.length > 0 ||
|
235
|
+
selectedTargets.hostGroups.length > 0 ||
|
236
|
+
hostsSearchQuery.length > 0;
|
212
237
|
const steps = [
|
213
238
|
{
|
214
239
|
name: WIZARD_TITLES.categoryAndTemplate,
|
@@ -238,7 +263,7 @@ export const JobWizard = ({ rerunData }) => {
|
|
238
263
|
/>
|
239
264
|
),
|
240
265
|
canJumpTo: isTemplate,
|
241
|
-
enableNext: isTemplate && valid.hostsAndInputs,
|
266
|
+
enableNext: isTemplate && valid.hostsAndInputs && areHostsSelected,
|
242
267
|
},
|
243
268
|
{
|
244
269
|
name: WIZARD_TITLES.advanced,
|
@@ -254,14 +279,26 @@ export const JobWizard = ({ rerunData }) => {
|
|
254
279
|
templateValues={templateValues}
|
255
280
|
/>
|
256
281
|
),
|
257
|
-
canJumpTo: isTemplate && valid.hostsAndInputs,
|
258
|
-
enableNext:
|
282
|
+
canJumpTo: isTemplate && valid.hostsAndInputs && areHostsSelected,
|
283
|
+
enableNext:
|
284
|
+
isTemplate &&
|
285
|
+
valid.hostsAndInputs &&
|
286
|
+
areHostsSelected &&
|
287
|
+
valid.advanced,
|
259
288
|
},
|
260
289
|
{
|
261
290
|
name: WIZARD_TITLES.schedule,
|
262
|
-
canJumpTo:
|
291
|
+
canJumpTo:
|
292
|
+
isTemplate &&
|
293
|
+
valid.hostsAndInputs &&
|
294
|
+
areHostsSelected &&
|
295
|
+
valid.advanced,
|
263
296
|
enableNext:
|
264
|
-
isTemplate &&
|
297
|
+
isTemplate &&
|
298
|
+
valid.hostsAndInputs &&
|
299
|
+
areHostsSelected &&
|
300
|
+
valid.advanced &&
|
301
|
+
valid.schedule,
|
265
302
|
steps: [
|
266
303
|
{
|
267
304
|
name: WIZARD_TITLES.typeOfExecution,
|
@@ -278,9 +315,17 @@ export const JobWizard = ({ rerunData }) => {
|
|
278
315
|
}}
|
279
316
|
/>
|
280
317
|
),
|
281
|
-
canJumpTo:
|
318
|
+
canJumpTo:
|
319
|
+
isTemplate &&
|
320
|
+
valid.hostsAndInputs &&
|
321
|
+
areHostsSelected &&
|
322
|
+
valid.advanced,
|
282
323
|
|
283
|
-
enableNext:
|
324
|
+
enableNext:
|
325
|
+
isTemplate &&
|
326
|
+
valid.hostsAndInputs &&
|
327
|
+
areHostsSelected &&
|
328
|
+
valid.advanced,
|
284
329
|
},
|
285
330
|
...(scheduleValue.scheduleType === SCHEDULE_TYPES.FUTURE
|
286
331
|
? [
|
@@ -298,10 +343,15 @@ export const JobWizard = ({ rerunData }) => {
|
|
298
343
|
}}
|
299
344
|
/>
|
300
345
|
),
|
301
|
-
canJumpTo:
|
346
|
+
canJumpTo:
|
347
|
+
isTemplate &&
|
348
|
+
valid.hostsAndInputs &&
|
349
|
+
areHostsSelected &&
|
350
|
+
valid.advanced,
|
302
351
|
enableNext:
|
303
352
|
isTemplate &&
|
304
353
|
valid.hostsAndInputs &&
|
354
|
+
areHostsSelected &&
|
305
355
|
valid.advanced &&
|
306
356
|
valid.schedule,
|
307
357
|
},
|
@@ -323,10 +373,15 @@ export const JobWizard = ({ rerunData }) => {
|
|
323
373
|
}}
|
324
374
|
/>
|
325
375
|
),
|
326
|
-
canJumpTo:
|
376
|
+
canJumpTo:
|
377
|
+
isTemplate &&
|
378
|
+
valid.hostsAndInputs &&
|
379
|
+
areHostsSelected &&
|
380
|
+
valid.advanced,
|
327
381
|
enableNext:
|
328
382
|
isTemplate &&
|
329
383
|
valid.hostsAndInputs &&
|
384
|
+
areHostsSelected &&
|
330
385
|
valid.advanced &&
|
331
386
|
valid.schedule,
|
332
387
|
},
|
@@ -349,39 +404,57 @@ export const JobWizard = ({ rerunData }) => {
|
|
349
404
|
),
|
350
405
|
nextButtonText: 'Run',
|
351
406
|
canJumpTo:
|
352
|
-
isTemplate &&
|
407
|
+
isTemplate &&
|
408
|
+
valid.advanced &&
|
409
|
+
valid.hostsAndInputs &&
|
410
|
+
areHostsSelected &&
|
411
|
+
valid.schedule,
|
353
412
|
enableNext:
|
354
413
|
isTemplate &&
|
355
414
|
valid.hostsAndInputs &&
|
415
|
+
areHostsSelected &&
|
356
416
|
valid.advanced &&
|
357
417
|
valid.schedule &&
|
358
|
-
!isSubmitting
|
418
|
+
!isSubmitting &&
|
419
|
+
!isStartsBeforeError,
|
359
420
|
},
|
360
421
|
];
|
361
422
|
const location = useForemanLocation();
|
362
423
|
const organization = useForemanOrganization();
|
424
|
+
const onSave = () => {
|
425
|
+
submit({
|
426
|
+
jobTemplateID,
|
427
|
+
templateValues,
|
428
|
+
advancedValues,
|
429
|
+
scheduleValue,
|
430
|
+
dispatch,
|
431
|
+
selectedTargets,
|
432
|
+
hostsSearchQuery,
|
433
|
+
location,
|
434
|
+
organization,
|
435
|
+
feature: routerSearch?.feature,
|
436
|
+
provider: templateResponse.provider_name,
|
437
|
+
advancedInputs: templateResponse.advanced_template_inputs,
|
438
|
+
});
|
439
|
+
};
|
363
440
|
return (
|
364
|
-
|
365
|
-
|
366
|
-
|
367
|
-
|
368
|
-
|
369
|
-
|
370
|
-
|
371
|
-
|
372
|
-
|
373
|
-
|
374
|
-
|
375
|
-
|
376
|
-
|
377
|
-
|
378
|
-
|
379
|
-
|
380
|
-
|
381
|
-
feature: routerSearch?.feature,
|
382
|
-
});
|
383
|
-
}}
|
384
|
-
/>
|
441
|
+
<>
|
442
|
+
{isStartsBeforeError && <StartsBeforeErrorAlert />}
|
443
|
+
<Wizard
|
444
|
+
onClose={() => history.goBack()}
|
445
|
+
navAriaLabel="Run Job steps"
|
446
|
+
steps={steps}
|
447
|
+
height="100%"
|
448
|
+
className="job-wizard"
|
449
|
+
onSave={onSave}
|
450
|
+
footer={
|
451
|
+
<Footer
|
452
|
+
canSubmit={!!steps[steps.length - 1].enableNext}
|
453
|
+
onSave={onSave}
|
454
|
+
/>
|
455
|
+
}
|
456
|
+
/>
|
457
|
+
</>
|
385
458
|
);
|
386
459
|
};
|
387
460
|
|
@@ -6,20 +6,15 @@
|
|
6
6
|
|
7
7
|
.pf-c-wizard__nav.pf-m-expanded {
|
8
8
|
z-index: calc(
|
9
|
-
var(--pf-c-
|
10
|
-
); // So the small screen navigation can be shown above the select box
|
9
|
+
var(--pf-c-wizard__toggle--ZIndex) + 2
|
10
|
+
); // So the small screen navigation can be shown above the select box and wizard body
|
11
11
|
}
|
12
12
|
|
13
13
|
.pf-c-wizard__main {
|
14
14
|
overflow: visible;
|
15
15
|
z-index: calc(
|
16
|
-
var(--pf-c-
|
17
|
-
); // So the select box can be shown above the wizard footer
|
18
|
-
}
|
19
|
-
.pf-c-wizard__nav {
|
20
|
-
z-index: calc(
|
21
|
-
var(--pf-c-wizard__footer--ZIndex) + 2
|
22
|
-
); // So the navigation box can be shown above the wizard body
|
16
|
+
var(--pf-c-wizard__toggle--ZIndex) + 1
|
17
|
+
); // So the select box can be shown above the wizard footer and navigation toggle
|
23
18
|
}
|
24
19
|
.pf-c-wizard__main-body {
|
25
20
|
max-width: 500px;
|
@@ -34,14 +29,8 @@
|
|
34
29
|
}
|
35
30
|
|
36
31
|
.target-hosts-and-inputs {
|
37
|
-
.
|
38
|
-
margin-
|
39
|
-
float: left;
|
40
|
-
clear: left;
|
41
|
-
display: block;
|
42
|
-
}
|
43
|
-
.clear-chips {
|
44
|
-
margin-top: 8px;
|
32
|
+
.pf-c-chip-group.pf-m-category {
|
33
|
+
margin-bottom: 10px;
|
45
34
|
}
|
46
35
|
.pf-c-select__toggle-typeahead {
|
47
36
|
border: 0px;
|
@@ -23,7 +23,7 @@ export const SCHEDULE_TYPES = {
|
|
23
23
|
};
|
24
24
|
|
25
25
|
export const WIZARD_TITLES = {
|
26
|
-
categoryAndTemplate: __('Category and
|
26
|
+
categoryAndTemplate: __('Category and template'),
|
27
27
|
hostsAndInputs: __('Target hosts and inputs'),
|
28
28
|
advanced: __('Advanced fields'),
|
29
29
|
schedule: __('Schedule'),
|
@@ -86,6 +86,7 @@ const JobWizardPageRerun = ({
|
|
86
86
|
<React.Fragment>
|
87
87
|
{jobOrganization?.id !== currentOrganization?.id && (
|
88
88
|
<Alert
|
89
|
+
isInline
|
89
90
|
className="job-wizard-alert"
|
90
91
|
variant="warning"
|
91
92
|
title={sprintf(
|
@@ -99,6 +100,7 @@ const JobWizardPageRerun = ({
|
|
99
100
|
)}
|
100
101
|
{jobLocation?.id !== currentLocation?.id && (
|
101
102
|
<Alert
|
103
|
+
isInline
|
102
104
|
className="job-wizard-alert"
|
103
105
|
variant="warning"
|
104
106
|
title={sprintf(
|
@@ -0,0 +1,17 @@
|
|
1
|
+
import React from 'react';
|
2
|
+
import { Divider, Alert } from '@patternfly/react-core';
|
3
|
+
import { translate as __ } from 'foremanReact/common/I18n';
|
4
|
+
|
5
|
+
export const StartsBeforeErrorAlert = () => (
|
6
|
+
<>
|
7
|
+
<Alert
|
8
|
+
variant="danger"
|
9
|
+
title={__("'Starts before' date must in the future")}
|
10
|
+
>
|
11
|
+
{__(
|
12
|
+
'Please go back to "Schedule" - "Future execution" step to fix the error'
|
13
|
+
)}
|
14
|
+
</Alert>
|
15
|
+
<Divider component="div" />
|
16
|
+
</>
|
17
|
+
);
|
@@ -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
|
};
|
@@ -318,6 +323,13 @@ export const jobInvocation = {
|
|
318
323
|
created_in_katello: false,
|
319
324
|
},
|
320
325
|
inputs: {
|
321
|
-
'inputs[plain hidden]':
|
326
|
+
'inputs[adv plain hidden]': {
|
327
|
+
advanced: true,
|
328
|
+
value: 'adv_test_command',
|
329
|
+
},
|
330
|
+
'inputs[plain hidden]': {
|
331
|
+
advanced: false,
|
332
|
+
value: 'test command',
|
333
|
+
},
|
322
334
|
},
|
323
335
|
};
|
@@ -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
|
104
|
+
});
|
105
|
+
|
106
|
+
const select = name =>
|
107
|
+
screen.getByRole('button', { name: `${name} toggle` });
|
108
|
+
fireEvent.click(select('hosts'));
|
109
|
+
await act(async () => {
|
110
|
+
fireEvent.click(screen.getByText('host1'));
|
88
111
|
});
|
89
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',
|
@@ -127,6 +154,10 @@ describe('Job wizard validation', () => {
|
|
127
154
|
});
|
128
155
|
|
129
156
|
expect(screen.getByText(WIZARD_TITLES.schedule)).toBeDisabled();
|
157
|
+
expect(screen.getByText('Run on selected hosts')).toHaveAttribute(
|
158
|
+
'aria-disabled',
|
159
|
+
'true'
|
160
|
+
);
|
130
161
|
expect(screen.getByText(WIZARD_TITLES.review)).toBeDisabled();
|
131
162
|
|
132
163
|
await act(async () => {
|
@@ -135,6 +166,11 @@ describe('Job wizard validation', () => {
|
|
135
166
|
});
|
136
167
|
});
|
137
168
|
|
169
|
+
expect(screen.getByText('Run on selected hosts')).toBeEnabled();
|
170
|
+
expect(screen.getByText('Run on selected hosts')).toHaveAttribute(
|
171
|
+
'aria-disabled',
|
172
|
+
'false'
|
173
|
+
);
|
138
174
|
expect(screen.getByText(WIZARD_TITLES.schedule)).toBeEnabled();
|
139
175
|
expect(screen.getByText(WIZARD_TITLES.review)).toBeEnabled();
|
140
176
|
});
|
@@ -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}>
|
@@ -51,7 +60,7 @@ describe('AdvancedFields', () => {
|
|
51
60
|
.simulate('click'); // Advanced step
|
52
61
|
|
53
62
|
await act(async () => {
|
54
|
-
jest.
|
63
|
+
jest.advanceTimersByTime(1000); // to handle pf4 date picker popover
|
55
64
|
});
|
56
65
|
const effectiveUserInput = () => wrapper.find('input#effective-user');
|
57
66
|
const advancedTemplateInput = () =>
|
@@ -83,7 +92,7 @@ describe('AdvancedFields', () => {
|
|
83
92
|
.simulate('click'); // Advanced step
|
84
93
|
|
85
94
|
await act(async () => {
|
86
|
-
jest.
|
95
|
+
jest.advanceTimersByTime(1000); // to handle pf4 date picker popover
|
87
96
|
});
|
88
97
|
expect(effectiveUserInput().prop('value')).toEqual(effectiveUesrValue);
|
89
98
|
expect(advancedTemplateInput().prop('value')).toEqual(
|
@@ -100,7 +109,7 @@ describe('AdvancedFields', () => {
|
|
100
109
|
);
|
101
110
|
await act(async () => {
|
102
111
|
fireEvent.click(screen.getByText(WIZARD_TITLES.advanced));
|
103
|
-
jest.
|
112
|
+
jest.advanceTimersByTime(1000); // to handle pf4 date picker popover
|
104
113
|
});
|
105
114
|
|
106
115
|
const searchValue = 'search test';
|
@@ -137,7 +146,7 @@ describe('AdvancedFields', () => {
|
|
137
146
|
fireEvent.change(timeField, {
|
138
147
|
target: { value: timeValue },
|
139
148
|
});
|
140
|
-
jest.
|
149
|
+
jest.advanceTimersByTime(1000); // to handle pf4 date picker popover
|
141
150
|
});
|
142
151
|
expect(
|
143
152
|
screen.getByLabelText('adv plain hidden', {
|
@@ -156,7 +165,7 @@ describe('AdvancedFields', () => {
|
|
156
165
|
|
157
166
|
await act(async () => {
|
158
167
|
await fireEvent.click(screen.getByText(WIZARD_TITLES.advanced));
|
159
|
-
jest.
|
168
|
+
jest.advanceTimersByTime(1000);
|
160
169
|
});
|
161
170
|
expect(textField.value).toBe(textValue);
|
162
171
|
expect(searchField.value).toBe(searchValue);
|
@@ -177,7 +186,7 @@ describe('AdvancedFields', () => {
|
|
177
186
|
);
|
178
187
|
await act(async () => {
|
179
188
|
fireEvent.click(screen.getByText(WIZARD_TITLES.advanced));
|
180
|
-
jest.
|
189
|
+
jest.advanceTimersByTime(1000); // to handle pf4 date picker popover
|
181
190
|
});
|
182
191
|
|
183
192
|
expect(
|
@@ -212,7 +221,7 @@ describe('AdvancedFields', () => {
|
|
212
221
|
);
|
213
222
|
await act(async () => {
|
214
223
|
fireEvent.click(screen.getByText(WIZARD_TITLES.advanced));
|
215
|
-
jest.
|
224
|
+
jest.advanceTimersByTime(1000); // to handle pf4 date picker popover
|
216
225
|
});
|
217
226
|
|
218
227
|
const textField = screen.getByLabelText('adv plain hidden', {
|
@@ -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
|
});
|
@@ -280,7 +294,7 @@ describe('AdvancedFields', () => {
|
|
280
294
|
);
|
281
295
|
await act(async () => {
|
282
296
|
fireEvent.click(screen.getByText(WIZARD_TITLES.advanced));
|
283
|
-
jest.
|
297
|
+
jest.advanceTimersByTime(1000); // to handle pf4 date picker popover
|
284
298
|
});
|
285
299
|
expect(
|
286
300
|
screen.getByLabelText('description preview', {
|
@@ -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
|
});
|
@@ -349,7 +368,7 @@ describe('AdvancedFields', () => {
|
|
349
368
|
);
|
350
369
|
await act(async () => {
|
351
370
|
fireEvent.click(screen.getByText(WIZARD_TITLES.advanced));
|
352
|
-
jest.
|
371
|
+
jest.advanceTimersByTime(1000); // to handle pf4 date picker popover
|
353
372
|
});
|
354
373
|
expect(
|
355
374
|
screen.getByLabelText('description preview', {
|
@@ -369,7 +388,7 @@ describe('AdvancedFields', () => {
|
|
369
388
|
);
|
370
389
|
await act(async () => {
|
371
390
|
fireEvent.click(screen.getByText(WIZARD_TITLES.advanced));
|
372
|
-
jest.
|
391
|
+
jest.advanceTimersByTime(1000); // to handle pf4 date picker popover
|
373
392
|
});
|
374
393
|
const resourceSelectField = screen.getByLabelText(
|
375
394
|
'adv resource select typeahead input'
|
data/webpack/JobWizard/steps/AdvancedFields/__tests__/__snapshots__/AdvancedFields.test.js.snap
CHANGED
@@ -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",
|
@@ -29,6 +29,7 @@ export const HostPreviewModal = ({ isOpen, setIsOpen, searchQuery }) => {
|
|
29
29
|
variant="link"
|
30
30
|
target="_blank"
|
31
31
|
rel="noreferrer"
|
32
|
+
isInline
|
32
33
|
>
|
33
34
|
{host}
|
34
35
|
</Button>
|
@@ -42,6 +43,7 @@ export const HostPreviewModal = ({ isOpen, setIsOpen, searchQuery }) => {
|
|
42
43
|
variant="link"
|
43
44
|
target="_blank"
|
44
45
|
rel="noreferrer"
|
46
|
+
isInline
|
45
47
|
>
|
46
48
|
{sprintf(
|
47
49
|
__('...and %s more'),
|
@@ -60,3 +62,6 @@ HostPreviewModal.propTypes = {
|
|
60
62
|
setIsOpen: PropTypes.func.isRequired,
|
61
63
|
searchQuery: PropTypes.string.isRequired,
|
62
64
|
};
|
65
|
+
HostPreviewModal.defaultPropTypes = {
|
66
|
+
searchQuery: '',
|
67
|
+
};
|