foreman_remote_execution 8.2.1 → 9.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/ruby_ci.yml +3 -1
- data/app/controllers/api/v2/job_invocations_controller.rb +0 -1
- data/app/controllers/ui_job_wizard_controller.rb +1 -6
- data/app/views/api/v2/job_invocations/base.json.rabl +1 -1
- data/app/views/job_invocations/show.html.erb +1 -1
- data/app/views/job_invocations/welcome.html.erb +1 -1
- data/db/migrate/20210816100932_rex_setting_category_to_dsl.rb +1 -1
- data/lib/foreman_remote_execution/engine.rb +1 -1
- data/lib/foreman_remote_execution/version.rb +1 -1
- data/locale/action_names.rb +2 -2
- data/locale/de/LC_MESSAGES/foreman_remote_execution.mo +0 -0
- data/locale/de/foreman_remote_execution.po +154 -266
- data/locale/en/LC_MESSAGES/foreman_remote_execution.mo +0 -0
- data/locale/en/foreman_remote_execution.po +24 -132
- data/locale/en_GB/LC_MESSAGES/foreman_remote_execution.mo +0 -0
- data/locale/en_GB/foreman_remote_execution.po +41 -149
- data/locale/es/LC_MESSAGES/foreman_remote_execution.mo +0 -0
- data/locale/es/foreman_remote_execution.po +210 -320
- data/locale/foreman_remote_execution.pot +211 -394
- data/locale/fr/LC_MESSAGES/foreman_remote_execution.mo +0 -0
- data/locale/fr/foreman_remote_execution.po +241 -353
- data/locale/ja/LC_MESSAGES/foreman_remote_execution.mo +0 -0
- data/locale/ja/foreman_remote_execution.po +261 -368
- data/locale/ko/LC_MESSAGES/foreman_remote_execution.mo +0 -0
- data/locale/ko/foreman_remote_execution.po +53 -161
- data/locale/pt_BR/LC_MESSAGES/foreman_remote_execution.mo +0 -0
- data/locale/pt_BR/foreman_remote_execution.po +225 -335
- data/locale/ru/LC_MESSAGES/foreman_remote_execution.mo +0 -0
- data/locale/ru/foreman_remote_execution.po +53 -161
- data/locale/zh_CN/LC_MESSAGES/foreman_remote_execution.mo +0 -0
- data/locale/zh_CN/foreman_remote_execution.po +359 -465
- data/locale/zh_TW/LC_MESSAGES/foreman_remote_execution.mo +0 -0
- data/locale/zh_TW/foreman_remote_execution.po +54 -162
- data/webpack/JobWizard/JobWizard.js +10 -52
- data/webpack/JobWizard/JobWizard.scss +1 -5
- data/webpack/JobWizard/__tests__/__snapshots__/integration.test.js.snap +0 -8
- data/webpack/JobWizard/__tests__/fixtures.js +0 -5
- data/webpack/JobWizard/__tests__/integration.test.js +0 -15
- data/webpack/JobWizard/__tests__/validation.test.js +0 -27
- data/webpack/JobWizard/autofill.js +0 -1
- data/webpack/JobWizard/steps/AdvancedFields/__tests__/AdvancedFields.test.js +0 -19
- data/webpack/JobWizard/steps/AdvancedFields/__tests__/__snapshots__/AdvancedFields.test.js.snap +1 -9
- data/webpack/JobWizard/steps/HostsAndInputs/HostPreviewModal.js +0 -3
- data/webpack/JobWizard/steps/HostsAndInputs/HostSearch.js +4 -28
- data/webpack/JobWizard/steps/HostsAndInputs/__tests__/HostsAndInputs.test.js +1 -31
- data/webpack/JobWizard/steps/HostsAndInputs/buildHostQuery.js +10 -16
- data/webpack/JobWizard/steps/HostsAndInputs/index.js +3 -55
- data/webpack/JobWizard/steps/Schedule/__tests__/Schedule.test.js +1 -21
- data/webpack/JobWizard/steps/form/Formatter.js +8 -30
- data/webpack/JobWizard/submit.js +2 -13
- metadata +3 -3
@@ -209,11 +209,6 @@ 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;
|
217
212
|
const steps = [
|
218
213
|
{
|
219
214
|
name: WIZARD_TITLES.categoryAndTemplate,
|
@@ -243,7 +238,7 @@ export const JobWizard = ({ rerunData }) => {
|
|
243
238
|
/>
|
244
239
|
),
|
245
240
|
canJumpTo: isTemplate,
|
246
|
-
enableNext: isTemplate && valid.hostsAndInputs
|
241
|
+
enableNext: isTemplate && valid.hostsAndInputs,
|
247
242
|
},
|
248
243
|
{
|
249
244
|
name: WIZARD_TITLES.advanced,
|
@@ -259,26 +254,14 @@ export const JobWizard = ({ rerunData }) => {
|
|
259
254
|
templateValues={templateValues}
|
260
255
|
/>
|
261
256
|
),
|
262
|
-
canJumpTo: isTemplate && valid.hostsAndInputs
|
263
|
-
enableNext:
|
264
|
-
isTemplate &&
|
265
|
-
valid.hostsAndInputs &&
|
266
|
-
areHostsSelected &&
|
267
|
-
valid.advanced,
|
257
|
+
canJumpTo: isTemplate && valid.hostsAndInputs,
|
258
|
+
enableNext: isTemplate && valid.hostsAndInputs && valid.advanced,
|
268
259
|
},
|
269
260
|
{
|
270
261
|
name: WIZARD_TITLES.schedule,
|
271
|
-
canJumpTo:
|
272
|
-
isTemplate &&
|
273
|
-
valid.hostsAndInputs &&
|
274
|
-
areHostsSelected &&
|
275
|
-
valid.advanced,
|
262
|
+
canJumpTo: isTemplate && valid.hostsAndInputs && valid.advanced,
|
276
263
|
enableNext:
|
277
|
-
isTemplate &&
|
278
|
-
valid.hostsAndInputs &&
|
279
|
-
areHostsSelected &&
|
280
|
-
valid.advanced &&
|
281
|
-
valid.schedule,
|
264
|
+
isTemplate && valid.hostsAndInputs && valid.advanced && valid.schedule,
|
282
265
|
steps: [
|
283
266
|
{
|
284
267
|
name: WIZARD_TITLES.typeOfExecution,
|
@@ -295,17 +278,9 @@ export const JobWizard = ({ rerunData }) => {
|
|
295
278
|
}}
|
296
279
|
/>
|
297
280
|
),
|
298
|
-
canJumpTo:
|
299
|
-
isTemplate &&
|
300
|
-
valid.hostsAndInputs &&
|
301
|
-
areHostsSelected &&
|
302
|
-
valid.advanced,
|
281
|
+
canJumpTo: isTemplate && valid.hostsAndInputs && valid.advanced,
|
303
282
|
|
304
|
-
enableNext:
|
305
|
-
isTemplate &&
|
306
|
-
valid.hostsAndInputs &&
|
307
|
-
areHostsSelected &&
|
308
|
-
valid.advanced,
|
283
|
+
enableNext: isTemplate && valid.hostsAndInputs && valid.advanced,
|
309
284
|
},
|
310
285
|
...(scheduleValue.scheduleType === SCHEDULE_TYPES.FUTURE
|
311
286
|
? [
|
@@ -323,15 +298,10 @@ export const JobWizard = ({ rerunData }) => {
|
|
323
298
|
}}
|
324
299
|
/>
|
325
300
|
),
|
326
|
-
canJumpTo:
|
327
|
-
isTemplate &&
|
328
|
-
valid.hostsAndInputs &&
|
329
|
-
areHostsSelected &&
|
330
|
-
valid.advanced,
|
301
|
+
canJumpTo: isTemplate && valid.hostsAndInputs && valid.advanced,
|
331
302
|
enableNext:
|
332
303
|
isTemplate &&
|
333
304
|
valid.hostsAndInputs &&
|
334
|
-
areHostsSelected &&
|
335
305
|
valid.advanced &&
|
336
306
|
valid.schedule,
|
337
307
|
},
|
@@ -353,15 +323,10 @@ export const JobWizard = ({ rerunData }) => {
|
|
353
323
|
}}
|
354
324
|
/>
|
355
325
|
),
|
356
|
-
canJumpTo:
|
357
|
-
isTemplate &&
|
358
|
-
valid.hostsAndInputs &&
|
359
|
-
areHostsSelected &&
|
360
|
-
valid.advanced,
|
326
|
+
canJumpTo: isTemplate && valid.hostsAndInputs && valid.advanced,
|
361
327
|
enableNext:
|
362
328
|
isTemplate &&
|
363
329
|
valid.hostsAndInputs &&
|
364
|
-
areHostsSelected &&
|
365
330
|
valid.advanced &&
|
366
331
|
valid.schedule,
|
367
332
|
},
|
@@ -384,15 +349,10 @@ export const JobWizard = ({ rerunData }) => {
|
|
384
349
|
),
|
385
350
|
nextButtonText: 'Run',
|
386
351
|
canJumpTo:
|
387
|
-
isTemplate &&
|
388
|
-
valid.advanced &&
|
389
|
-
valid.hostsAndInputs &&
|
390
|
-
areHostsSelected &&
|
391
|
-
valid.schedule,
|
352
|
+
isTemplate && valid.hostsAndInputs && valid.advanced && valid.schedule,
|
392
353
|
enableNext:
|
393
354
|
isTemplate &&
|
394
355
|
valid.hostsAndInputs &&
|
395
|
-
areHostsSelected &&
|
396
356
|
valid.advanced &&
|
397
357
|
valid.schedule &&
|
398
358
|
!isSubmitting,
|
@@ -419,8 +379,6 @@ export const JobWizard = ({ rerunData }) => {
|
|
419
379
|
location,
|
420
380
|
organization,
|
421
381
|
feature: routerSearch?.feature,
|
422
|
-
provider: templateResponse.provider_name,
|
423
|
-
advancedInputs: templateResponse.advanced_template_inputs,
|
424
382
|
});
|
425
383
|
}}
|
426
384
|
/>
|
@@ -1,4 +1,5 @@
|
|
1
1
|
.job-wizard {
|
2
|
+
font-size: var(--pf-global--FontSize--md);
|
2
3
|
.wizard-title {
|
3
4
|
margin-bottom: 25px;
|
4
5
|
}
|
@@ -134,11 +135,6 @@
|
|
134
135
|
margin-left: 10px;
|
135
136
|
}
|
136
137
|
}
|
137
|
-
.foreman-search-field {
|
138
|
-
.autocomplete-search-btn {
|
139
|
-
display: none;
|
140
|
-
}
|
141
|
-
}
|
142
138
|
.pf-c-radio__body {
|
143
139
|
font-size: var(--pf-c-radio__label--FontSize);
|
144
140
|
}
|
@@ -7,14 +7,6 @@ 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
|
-
},
|
18
10
|
Object {
|
19
11
|
"key": "JOB_TEMPLATES",
|
20
12
|
"type": "get",
|
@@ -18,15 +18,6 @@ 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
|
-
});
|
30
21
|
it('should select template', async () => {
|
31
22
|
api.get.mockImplementation(({ handleSuccess, ...action }) => {
|
32
23
|
if (action.key === 'JOB_CATEGORIES') {
|
@@ -42,13 +33,7 @@ describe('Job wizard fill', () => {
|
|
42
33
|
handleSuccess({
|
43
34
|
data: jobTemplate,
|
44
35
|
});
|
45
|
-
} else if (action.key === 'HOST_IDS') {
|
46
|
-
handleSuccess &&
|
47
|
-
handleSuccess({
|
48
|
-
data: { results: [{ name: 'host1' }, { name: 'host3' }] },
|
49
|
-
});
|
50
36
|
}
|
51
|
-
|
52
37
|
return { type: 'get', ...action };
|
53
38
|
});
|
54
39
|
selectors.selectJobTemplate.mockRestore();
|
@@ -41,26 +41,11 @@ 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
|
45
44
|
});
|
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();
|
56
45
|
const textField = screen.getByLabelText('plain hidden', {
|
57
46
|
selector: 'textarea',
|
58
47
|
});
|
59
48
|
await act(async () => {
|
60
|
-
fireEvent.click(
|
61
|
-
// Close the select
|
62
|
-
select('hosts')
|
63
|
-
);
|
64
49
|
await fireEvent.change(textField, {
|
65
50
|
target: { value: 'text' },
|
66
51
|
});
|
@@ -100,20 +85,8 @@ describe('Job wizard validation', () => {
|
|
100
85
|
// setup
|
101
86
|
await act(async () => {
|
102
87
|
fireEvent.click(screen.getByText(WIZARD_TITLES.hostsAndInputs));
|
103
|
-
await new Promise(resolve => setTimeout(resolve, 0)); // to resolve gql
|
104
88
|
});
|
105
|
-
|
106
|
-
const select = name =>
|
107
|
-
screen.getByRole('button', { name: `${name} toggle` });
|
108
|
-
fireEvent.click(select('hosts'));
|
109
89
|
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
|
-
);
|
117
90
|
await fireEvent.change(
|
118
91
|
screen.getByLabelText('plain hidden', {
|
119
92
|
selector: 'textarea',
|
@@ -72,7 +72,6 @@ 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] }));
|
76
75
|
} else {
|
77
76
|
const { value, advanced } = rest[key];
|
78
77
|
if (advanced) {
|
@@ -26,15 +26,6 @@ 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
|
-
});
|
38
29
|
it('should save data between steps for advanced fields', async () => {
|
39
30
|
const wrapper = mount(
|
40
31
|
<MockedProvider mocks={gqlMock} addTypename={false}>
|
@@ -279,11 +270,6 @@ describe('AdvancedFields', () => {
|
|
279
270
|
handleSuccess({
|
280
271
|
data: { results: [jobTemplate] },
|
281
272
|
});
|
282
|
-
} else if (action.key === 'HOST_IDS') {
|
283
|
-
handleSuccess &&
|
284
|
-
handleSuccess({
|
285
|
-
data: { results: [{ name: 'host1' }, { name: 'host3' }] },
|
286
|
-
});
|
287
273
|
}
|
288
274
|
return { type: 'get', ...action };
|
289
275
|
});
|
@@ -353,11 +339,6 @@ describe('AdvancedFields', () => {
|
|
353
339
|
handleSuccess({
|
354
340
|
data: { results: [jobTemplate] },
|
355
341
|
});
|
356
|
-
} else if (action.key === 'HOST_IDS') {
|
357
|
-
handleSuccess &&
|
358
|
-
handleSuccess({
|
359
|
-
data: { results: [{ name: 'host1' }, { name: 'host3' }] },
|
360
|
-
});
|
361
342
|
}
|
362
343
|
return { type: 'get', ...action };
|
363
344
|
});
|
data/webpack/JobWizard/steps/AdvancedFields/__tests__/__snapshots__/AdvancedFields.test.js.snap
CHANGED
@@ -7,14 +7,6 @@ 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
|
-
},
|
18
10
|
Object {
|
19
11
|
"key": "JOB_TEMPLATES",
|
20
12
|
"type": "get",
|
@@ -57,7 +49,7 @@ Array [
|
|
57
49
|
"port": null,
|
58
50
|
"preventInvalidHostname": false,
|
59
51
|
"protocol": null,
|
60
|
-
"query": "resource=ForemanTasks%3A%3ATask",
|
52
|
+
"query": "resource=ForemanTasks%3A%3ATask&name=some+search",
|
61
53
|
"urn": null,
|
62
54
|
"username": null,
|
63
55
|
},
|
@@ -1,33 +1,10 @@
|
|
1
|
-
import React
|
2
|
-
import { useSelector, useDispatch } from 'react-redux';
|
1
|
+
import React from 'react';
|
3
2
|
import PropTypes from 'prop-types';
|
4
3
|
import SearchBar from 'foremanReact/components/SearchBar';
|
5
4
|
import { getControllerSearchProps } from 'foremanReact/constants';
|
6
|
-
import { getResults } from 'foremanReact/components/AutoComplete/AutoCompleteActions';
|
7
|
-
import { TRIGGERS } from 'foremanReact/components/AutoComplete/AutoCompleteConstants';
|
8
5
|
import { hostsController, hostQuerySearchID } from '../../JobWizardConstants';
|
9
|
-
import { noop } from '../../../helpers';
|
10
6
|
|
11
7
|
export const HostSearch = ({ value, setValue }) => {
|
12
|
-
const searchQuery = useSelector(
|
13
|
-
state => state.autocomplete?.[hostQuerySearchID]?.searchQuery
|
14
|
-
);
|
15
|
-
useEffect(() => {
|
16
|
-
setValue(searchQuery || '');
|
17
|
-
}, [setValue, searchQuery]);
|
18
|
-
const dispatch = useDispatch();
|
19
|
-
const setSearch = newSearchQuery => {
|
20
|
-
dispatch(
|
21
|
-
getResults({
|
22
|
-
url: '/hosts/auto_complete_search',
|
23
|
-
searchQuery: newSearchQuery,
|
24
|
-
controller: 'hostsController',
|
25
|
-
trigger: TRIGGERS.INPUT_CHANGE,
|
26
|
-
id: hostQuerySearchID,
|
27
|
-
})
|
28
|
-
);
|
29
|
-
};
|
30
|
-
|
31
8
|
const props = getControllerSearchProps(hostsController, hostQuerySearchID);
|
32
9
|
return (
|
33
10
|
<div className="foreman-search-field">
|
@@ -37,12 +14,11 @@ export const HostSearch = ({ value, setValue }) => {
|
|
37
14
|
autocomplete: {
|
38
15
|
id: hostQuerySearchID,
|
39
16
|
url: '/hosts/auto_complete_search',
|
40
|
-
|
17
|
+
searchQuery: value,
|
41
18
|
},
|
42
19
|
}}
|
43
|
-
onSearch={
|
44
|
-
|
45
|
-
onBookmarkClick={search => setSearch(search)}
|
20
|
+
onSearch={null}
|
21
|
+
onSearchChange={search => setValue(search)}
|
46
22
|
/>
|
47
23
|
</div>
|
48
24
|
);
|
@@ -30,27 +30,6 @@ 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);
|
54
33
|
await act(async () => {
|
55
34
|
fireEvent.click(screen.getByText('host1'));
|
56
35
|
fireEvent.click(screen.getByText('host2'));
|
@@ -172,9 +151,8 @@ describe('Hosts', () => {
|
|
172
151
|
|
173
152
|
it('input fill from url', async () => {
|
174
153
|
const inputText = 'test text';
|
175
|
-
const advancedInputText = 'test adv text';
|
176
154
|
routerSelectors.selectRouterLocation.mockImplementation(() => ({
|
177
|
-
search: `
|
155
|
+
search: `feature=test_feature&inputs[plain hidden]=${inputText}`,
|
178
156
|
}));
|
179
157
|
render(
|
180
158
|
<MockedProvider mocks={gqlMock} addTypename={false}>
|
@@ -197,13 +175,5 @@ describe('Hosts', () => {
|
|
197
175
|
selector: 'textarea',
|
198
176
|
});
|
199
177
|
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);
|
208
178
|
});
|
209
179
|
});
|
@@ -1,24 +1,18 @@
|
|
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
|
-
|
9
|
+
.join(',')}))`;
|
10
|
+
return [
|
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
|
-
|
17
|
-
|
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';
|
14
|
+
search.length ? `(${search})` : false,
|
15
|
+
]
|
16
|
+
.filter(Boolean)
|
17
|
+
.join(' or ');
|
24
18
|
};
|
@@ -13,7 +13,6 @@ import { FilterIcon } from '@patternfly/react-icons';
|
|
13
13
|
import { debounce } from 'lodash';
|
14
14
|
import { get } from 'foremanReact/redux/API';
|
15
15
|
import { translate as __ } from 'foremanReact/common/I18n';
|
16
|
-
import { resetData } from 'foremanReact/components/AutoComplete/AutoCompleteActions';
|
17
16
|
import {
|
18
17
|
selectTemplateInputs,
|
19
18
|
selectWithKatello,
|
@@ -31,8 +30,6 @@ import {
|
|
31
30
|
HOST_COLLECTIONS,
|
32
31
|
HOST_GROUPS,
|
33
32
|
hostMethods,
|
34
|
-
hostsController,
|
35
|
-
hostQuerySearchID,
|
36
33
|
HOSTS_API,
|
37
34
|
HOSTS_TO_PREVIEW_AMOUNT,
|
38
35
|
DEBOUNCE_API,
|
@@ -54,30 +51,6 @@ const HostsAndInputs = ({
|
|
54
51
|
const isLoading = useSelector(selectIsLoadingHosts);
|
55
52
|
const templateInputs = useSelector(selectTemplateInputs);
|
56
53
|
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
|
-
]);
|
81
54
|
useEffect(() => {
|
82
55
|
debounce(() => {
|
83
56
|
dispatch(
|
@@ -124,12 +97,8 @@ const HostsAndInputs = ({
|
|
124
97
|
};
|
125
98
|
|
126
99
|
const clearSearch = () => {
|
127
|
-
dispatch(resetData(hostsController, hostQuerySearchID));
|
128
100
|
setHostsSearchQuery('');
|
129
101
|
};
|
130
|
-
const [errorText, setErrorText] = useState(
|
131
|
-
__('Please select at least one host')
|
132
|
-
);
|
133
102
|
return (
|
134
103
|
<div className="target-hosts-and-inputs">
|
135
104
|
<WizardTitle title={WIZARD_TITLES.hostsAndInputs} />
|
@@ -141,13 +110,8 @@ const HostsAndInputs = ({
|
|
141
110
|
/>
|
142
111
|
)}
|
143
112
|
<Form>
|
144
|
-
<FormGroup
|
145
|
-
|
146
|
-
id="host-selection"
|
147
|
-
helperTextInvalid={errorText}
|
148
|
-
validated={isError ? 'error' : 'default'}
|
149
|
-
>
|
150
|
-
<InputGroup onBlur={() => setWasFocus(true)}>
|
113
|
+
<FormGroup fieldId="host_selection" id="host-selection">
|
114
|
+
<InputGroup>
|
151
115
|
<SelectField
|
152
116
|
isRequired
|
153
117
|
className="target-method-select"
|
@@ -159,23 +123,7 @@ const HostsAndInputs = ({
|
|
159
123
|
}
|
160
124
|
return true;
|
161
125
|
})}
|
162
|
-
setValue={
|
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
|
-
}}
|
126
|
+
setValue={setHostMethod}
|
179
127
|
value={hostMethod}
|
180
128
|
/>
|
181
129
|
{hostMethod === hostMethods.searchQuery && (
|
@@ -39,35 +39,15 @@ 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
|
-
});
|
47
42
|
}
|
48
43
|
return { type: 'get', ...action };
|
49
44
|
});
|
50
45
|
|
51
46
|
const mockStore = configureMockStore([]);
|
52
|
-
const store = mockStore({
|
53
|
-
HOSTS_API: {
|
54
|
-
response: {
|
55
|
-
subtotal: 3,
|
56
|
-
},
|
57
|
-
},
|
58
|
-
});
|
47
|
+
const store = mockStore({});
|
59
48
|
jest.useFakeTimers();
|
60
49
|
|
61
50
|
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
|
-
});
|
71
51
|
it('sub steps appear', () => {
|
72
52
|
render(
|
73
53
|
<Provider store={store}>
|