foreman_remote_execution 16.5.3 → 16.6.4
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/Rakefile +0 -15
- data/lib/foreman_remote_execution/version.rb +1 -1
- data/webpack/JobInvocationDetail/JobInvocationActions.js +7 -0
- data/webpack/JobInvocationDetail/JobInvocationHostTable.js +5 -2
- data/webpack/JobInvocationDetail/TemplateInvocationComponents/OutputCodeBlock.js +6 -3
- data/webpack/JobInvocationDetail/__tests__/OutputCodeBlock.test.js +1 -0
- data/webpack/JobInvocationDetail/__tests__/fixtures.js +9 -0
- data/webpack/JobWizard/JobWizard.js +7 -0
- data/webpack/JobWizard/JobWizardConstants.js +5 -0
- data/webpack/JobWizard/JobWizardSelectors.js +8 -0
- data/webpack/JobWizard/PermissionDenied.js +5 -2
- data/webpack/JobWizard/__tests__/JobWizardPageRerun.test.js +53 -9
- data/webpack/JobWizard/__tests__/fixtures.js +24 -0
- data/webpack/JobWizard/autofill.js +57 -4
- data/webpack/JobWizard/steps/AdvancedFields/__tests__/AdvancedFields.test.js +7 -2
- data/webpack/JobWizard/steps/HostsAndInputs/HostSearch.js +31 -7
- data/webpack/JobWizard/steps/HostsAndInputs/__tests__/HostsAndInputs.test.js +95 -1
- data/webpack/JobWizard/steps/HostsAndInputs/index.js +5 -0
- data/webpack/JobWizard/steps/Schedule/__tests__/Schedule.test.js +2 -0
- data/webpack/JobWizard/submit.js +15 -2
- data/webpack/react_app/components/RegistrationExtension/RexPull.js +8 -5
- data/webpack/react_app/components/TargetingHosts/__tests__/__snapshots__/TargetingHostsPage.test.js.snap +5 -1
- metadata +3 -33
- data/webpack/JobWizard/steps/AdvancedFields/__tests__/__snapshots__/AdvancedFields.test.js.snap +0 -90
- data/webpack/__mocks__/foremanReact/components/SearchBar.js +0 -19
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: c9b021c23fae39af103f3ac3bdb0fd3e208b74fb8ad234f66f7770a5e4dfc78f
|
|
4
|
+
data.tar.gz: 4fd6498051640caae5cf6e4580d01106883a0f33d486b672a0d77ed49205e52c
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: bf4e127076278dca8d3ec7d4b86a625a89bb95c4a4c5cd728e9207e8ff3151f983965061498bbfd813c6d9d08f49ec59f9ba2bc06be113f8e721e8f04dfc0285
|
|
7
|
+
data.tar.gz: 0124e5ae5e0f484269adf05e9e9e3aa10e1262c4c6f635707dee035f217a5206565bc231fa65dee356609ce6e9db332d7c1faf96b8d1b7b3760483171997e5fd
|
data/Rakefile
CHANGED
|
@@ -3,21 +3,6 @@ begin
|
|
|
3
3
|
rescue LoadError
|
|
4
4
|
puts 'You must `gem install bundler` and `bundle install` to run rake tasks'
|
|
5
5
|
end
|
|
6
|
-
begin
|
|
7
|
-
require 'rdoc/task'
|
|
8
|
-
rescue LoadError
|
|
9
|
-
require 'rdoc/rdoc'
|
|
10
|
-
require 'rake/rdoctask'
|
|
11
|
-
RDoc::Task = Rake::RDocTask
|
|
12
|
-
end
|
|
13
|
-
|
|
14
|
-
RDoc::Task.new(:rdoc) do |rdoc|
|
|
15
|
-
rdoc.rdoc_dir = 'rdoc'
|
|
16
|
-
rdoc.title = 'ForemanRemoteExecution'
|
|
17
|
-
rdoc.options << '--line-numbers'
|
|
18
|
-
rdoc.rdoc_files.include('README.rdoc')
|
|
19
|
-
rdoc.rdoc_files.include('lib/**/*.rb')
|
|
20
|
-
end
|
|
21
6
|
|
|
22
7
|
APP_RAKEFILE = File.expand_path('../test/dummy/Rakefile', __FILE__)
|
|
23
8
|
|
|
@@ -24,6 +24,13 @@ export const getJobInvocation = url => dispatch => {
|
|
|
24
24
|
handleError: () => {
|
|
25
25
|
dispatch(stopInterval(JOB_INVOCATION_KEY));
|
|
26
26
|
},
|
|
27
|
+
errorToast: ({ response }) =>
|
|
28
|
+
// eslint-disable-next-line camelcase
|
|
29
|
+
response?.data?.error?.full_messages?.[0] ||
|
|
30
|
+
// eslint-disable-next-line camelcase
|
|
31
|
+
response?.data?.error?.full_messages ||
|
|
32
|
+
response?.data?.error?.message ||
|
|
33
|
+
'Error',
|
|
27
34
|
}),
|
|
28
35
|
1000
|
|
29
36
|
);
|
|
@@ -1,12 +1,14 @@
|
|
|
1
1
|
/* eslint-disable max-lines */
|
|
2
2
|
/* eslint-disable camelcase */
|
|
3
3
|
import {
|
|
4
|
+
Icon,
|
|
4
5
|
EmptyState,
|
|
5
6
|
EmptyStateBody,
|
|
6
7
|
EmptyStateHeader,
|
|
7
8
|
EmptyStateVariant,
|
|
8
9
|
ToolbarItem,
|
|
9
10
|
} from '@patternfly/react-core';
|
|
11
|
+
import { AddCircleOIcon } from '@patternfly/react-icons';
|
|
10
12
|
import { ExpandableRowContent, Tbody, Td, Tr } from '@patternfly/react-table';
|
|
11
13
|
import { useDispatch } from 'react-redux';
|
|
12
14
|
import { APIActions } from 'foremanReact/redux/API';
|
|
@@ -22,7 +24,6 @@ import {
|
|
|
22
24
|
import { getPageStats } from 'foremanReact/components/PF4/TableIndexPage/Table/helpers';
|
|
23
25
|
import TableIndexPage from 'foremanReact/components/PF4/TableIndexPage/TableIndexPage';
|
|
24
26
|
import { getControllerSearchProps } from 'foremanReact/constants';
|
|
25
|
-
import { Icon } from 'patternfly-react';
|
|
26
27
|
import PropTypes from 'prop-types';
|
|
27
28
|
import React, {
|
|
28
29
|
useEffect,
|
|
@@ -339,7 +340,9 @@ const JobInvocationHostTable = ({
|
|
|
339
340
|
<Td colSpan={100}>
|
|
340
341
|
<EmptyState variant={EmptyStateVariant.xl}>
|
|
341
342
|
<span className="empty-state-icon">
|
|
342
|
-
<Icon
|
|
343
|
+
<Icon size="xl" iconSize="xl">
|
|
344
|
+
<AddCircleOIcon name="add-circle-o" />
|
|
345
|
+
</Icon>
|
|
343
346
|
</span>
|
|
344
347
|
<EmptyStateHeader
|
|
345
348
|
titleText={<>{__('No Results')}</>}
|
|
@@ -11,7 +11,7 @@ import { translate as __ } from 'foremanReact/common/I18n';
|
|
|
11
11
|
export const OutputCodeBlock = ({ code, showOutputType, scrollElement }) => {
|
|
12
12
|
let lineCounter = 0;
|
|
13
13
|
// eslint-disable-next-line no-control-regex
|
|
14
|
-
const COLOR_PATTERN = /\x1b\[
|
|
14
|
+
const COLOR_PATTERN = /\x1b\[[\d;]*m/g;
|
|
15
15
|
const CONSOLE_COLOR = {
|
|
16
16
|
'31': 'red',
|
|
17
17
|
'32': 'lightgreen',
|
|
@@ -27,12 +27,15 @@ export const OutputCodeBlock = ({ code, showOutputType, scrollElement }) => {
|
|
|
27
27
|
'95': 'violet',
|
|
28
28
|
'96': 'turquoise',
|
|
29
29
|
'0': 'default',
|
|
30
|
+
'39': 'default',
|
|
30
31
|
};
|
|
31
32
|
|
|
32
33
|
const colorizeLine = line => {
|
|
33
34
|
line = line.replace(COLOR_PATTERN, seq => {
|
|
34
|
-
const
|
|
35
|
-
|
|
35
|
+
const codes = seq.match(/(\d+)/g) || [];
|
|
36
|
+
const lastColorCode =
|
|
37
|
+
[...codes].reverse().find(code_ => code_ in CONSOLE_COLOR) || '0';
|
|
38
|
+
return `{{{format color:${lastColorCode}}}}`;
|
|
36
39
|
});
|
|
37
40
|
|
|
38
41
|
let currentColor = 'default';
|
|
@@ -31,6 +31,7 @@ describe('OutputCodeBlock', () => {
|
|
|
31
31
|
expect(screen.getByText('This is green text')).toHaveStyle(
|
|
32
32
|
'color: lightgreen'
|
|
33
33
|
);
|
|
34
|
+
expect(screen.getByText('Compound red text')).toHaveStyle('color: red');
|
|
34
35
|
});
|
|
35
36
|
|
|
36
37
|
test('displays no output message when filtered', () => {
|
|
@@ -196,6 +196,15 @@ export const jobInvocationOutput = [
|
|
|
196
196
|
timestamp: 1733931148.2044532,
|
|
197
197
|
},
|
|
198
198
|
|
|
199
|
+
{
|
|
200
|
+
id: 1960,
|
|
201
|
+
template_invocation_id: templateInvocationID,
|
|
202
|
+
timestamp: 1733931149.2044532,
|
|
203
|
+
meta: null,
|
|
204
|
+
external_id: '0',
|
|
205
|
+
output_type: 'stdout',
|
|
206
|
+
output: '\u001b[0;31mCompound red text\u001b[0m\n',
|
|
207
|
+
},
|
|
199
208
|
{
|
|
200
209
|
id: 1907,
|
|
201
210
|
template_invocation_id: templateInvocationID,
|
|
@@ -62,10 +62,12 @@ export const JobWizard = ({ rerunData }) => {
|
|
|
62
62
|
hostGroups: [],
|
|
63
63
|
});
|
|
64
64
|
const [hostsSearchQuery, setHostsSearchQuery] = useState('');
|
|
65
|
+
const [selectedBookmark, setSelectedBookmark] = useState(null);
|
|
65
66
|
const [fills, setFills] = useState(
|
|
66
67
|
rerunData
|
|
67
68
|
? {
|
|
68
69
|
search: rerunData?.targeting?.search_query,
|
|
70
|
+
bookmark_id: rerunData?.targeting?.bookmark_id,
|
|
69
71
|
...rerunData.inputs,
|
|
70
72
|
...routerSearch,
|
|
71
73
|
}
|
|
@@ -251,6 +253,7 @@ export const JobWizard = ({ rerunData }) => {
|
|
|
251
253
|
setFills,
|
|
252
254
|
setSelectedTargets,
|
|
253
255
|
setHostsSearchQuery,
|
|
256
|
+
setSelectedBookmark,
|
|
254
257
|
setJobTemplateID,
|
|
255
258
|
setTemplateValues,
|
|
256
259
|
setAdvancedValues,
|
|
@@ -298,6 +301,8 @@ export const JobWizard = ({ rerunData }) => {
|
|
|
298
301
|
setSelected={setSelectedTargets}
|
|
299
302
|
hostsSearchQuery={hostsSearchQuery}
|
|
300
303
|
setHostsSearchQuery={setHostsSearchQuery}
|
|
304
|
+
selectedBookmark={selectedBookmark}
|
|
305
|
+
setSelectedBookmark={setSelectedBookmark}
|
|
301
306
|
/>
|
|
302
307
|
),
|
|
303
308
|
canJumpTo: isTemplate,
|
|
@@ -474,6 +479,7 @@ export const JobWizard = ({ rerunData }) => {
|
|
|
474
479
|
dispatch,
|
|
475
480
|
selectedTargets,
|
|
476
481
|
hostsSearchQuery,
|
|
482
|
+
selectedBookmark,
|
|
477
483
|
location,
|
|
478
484
|
organization,
|
|
479
485
|
feature,
|
|
@@ -507,6 +513,7 @@ JobWizard.propTypes = {
|
|
|
507
513
|
job_category: PropTypes.string,
|
|
508
514
|
targeting: PropTypes.shape({
|
|
509
515
|
search_query: PropTypes.string,
|
|
516
|
+
bookmark_id: PropTypes.number,
|
|
510
517
|
targeting_type: PropTypes.string,
|
|
511
518
|
randomized_ordering: PropTypes.bool,
|
|
512
519
|
}),
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { translate as __ } from 'foremanReact/common/I18n';
|
|
2
2
|
import { foremanUrl } from 'foremanReact/common/helpers';
|
|
3
|
+
import { getControllerSearchProps } from 'foremanReact/constants';
|
|
3
4
|
|
|
4
5
|
export const JOB_TEMPLATES = 'JOB_TEMPLATES';
|
|
5
6
|
export const JOB_CATEGORIES = 'JOB_CATEGORIES';
|
|
@@ -61,6 +62,10 @@ export const hostMethods = {
|
|
|
61
62
|
|
|
62
63
|
export const hostQuerySearchID = 'mainHostQuery';
|
|
63
64
|
export const hostsController = 'hosts';
|
|
65
|
+
export const hostsSearchProps = getControllerSearchProps(
|
|
66
|
+
hostsController,
|
|
67
|
+
hostQuerySearchID
|
|
68
|
+
);
|
|
64
69
|
|
|
65
70
|
export const dataName = {
|
|
66
71
|
[HOSTS]: 'hosts',
|
|
@@ -9,6 +9,8 @@ import {
|
|
|
9
9
|
} from 'foremanReact/redux/API/APISelectors';
|
|
10
10
|
import { STATUS } from 'foremanReact/constants';
|
|
11
11
|
import { selectRouterLocation } from 'foremanReact/routes/RouterSelector';
|
|
12
|
+
import { BOOKMARKS } from 'foremanReact/components/PF4/Bookmarks/BookmarksConstants';
|
|
13
|
+
import { selectBookmarksResults } from 'foremanReact/components/PF4/Bookmarks/BookmarksSelectors';
|
|
12
14
|
|
|
13
15
|
import {
|
|
14
16
|
JOB_TEMPLATES,
|
|
@@ -134,3 +136,9 @@ export const selectRouterSearch = state => {
|
|
|
134
136
|
const { search } = selectRouterLocation(state) || {};
|
|
135
137
|
return URI.parseQuery(search);
|
|
136
138
|
};
|
|
139
|
+
|
|
140
|
+
const HOSTS_CONTROLLER = 'hosts';
|
|
141
|
+
const BOOKMARKS_HOSTS_KEY = `${BOOKMARKS}_${HOSTS_CONTROLLER.toUpperCase()}`;
|
|
142
|
+
|
|
143
|
+
export const selectHostBookmarks = state =>
|
|
144
|
+
selectBookmarksResults(state, BOOKMARKS_HOSTS_KEY, HOSTS_CONTROLLER);
|
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
2
|
import PropTypes from 'prop-types';
|
|
3
3
|
import { translate as __ } from 'foremanReact/common/I18n';
|
|
4
|
-
import {
|
|
4
|
+
import { LockIcon } from '@patternfly/react-icons';
|
|
5
5
|
import {
|
|
6
|
+
Icon,
|
|
6
7
|
Button,
|
|
7
8
|
EmptyState,
|
|
8
9
|
EmptyStateVariant,
|
|
@@ -36,7 +37,9 @@ const PermissionDenied = ({ missingPermissions, setProceedAnyway }) => {
|
|
|
36
37
|
return (
|
|
37
38
|
<EmptyState variant={EmptyStateVariant.xl}>
|
|
38
39
|
<span className="empty-state-icon">
|
|
39
|
-
<Icon
|
|
40
|
+
<Icon size="xl" iconSize="xl">
|
|
41
|
+
<LockIcon name="lock" />
|
|
42
|
+
</Icon>
|
|
40
43
|
</span>
|
|
41
44
|
<EmptyStateHeader
|
|
42
45
|
titleText={<>{__('Permission Denied')}</>}
|
|
@@ -3,21 +3,19 @@ import { Provider } from 'react-redux';
|
|
|
3
3
|
import { render, fireEvent, screen, act } from '@testing-library/react';
|
|
4
4
|
import { MockedProvider } from '@apollo/client/testing';
|
|
5
5
|
|
|
6
|
-
import * as APIHooks from 'foremanReact/common/hooks/API/APIHooks';
|
|
7
6
|
import * as api from 'foremanReact/redux/API';
|
|
8
7
|
import JobWizardPageRerun from '../JobWizardPageRerun';
|
|
9
8
|
import * as selectors from '../JobWizardSelectors';
|
|
10
|
-
import {
|
|
9
|
+
import {
|
|
10
|
+
testSetup,
|
|
11
|
+
mockApi,
|
|
12
|
+
gqlMock,
|
|
13
|
+
jobInvocation,
|
|
14
|
+
bookmarksList,
|
|
15
|
+
} from './fixtures';
|
|
11
16
|
|
|
12
17
|
const store = testSetup(selectors, api);
|
|
13
18
|
mockApi(api);
|
|
14
|
-
jest.spyOn(APIHooks, 'useAPI');
|
|
15
|
-
APIHooks.useAPI.mockImplementation((action, url) => {
|
|
16
|
-
if (url === '/ui_job_wizard/job_invocation?id=57') {
|
|
17
|
-
return { response: jobInvocation, status: 'RESOLVED' };
|
|
18
|
-
}
|
|
19
|
-
return {};
|
|
20
|
-
});
|
|
21
19
|
|
|
22
20
|
describe('Job wizard fill', () => {
|
|
23
21
|
it('fill defaults into fields', async () => {
|
|
@@ -76,4 +74,50 @@ describe('Job wizard fill', () => {
|
|
|
76
74
|
}).value
|
|
77
75
|
).toBe('6');
|
|
78
76
|
});
|
|
77
|
+
|
|
78
|
+
it('fills bookmark on rerun when job used a bookmark', async () => {
|
|
79
|
+
const bookmark = bookmarksList[0];
|
|
80
|
+
const jobWithBookmark = {
|
|
81
|
+
...jobInvocation,
|
|
82
|
+
job: {
|
|
83
|
+
...jobInvocation.job,
|
|
84
|
+
targeting: {
|
|
85
|
+
...jobInvocation.job.targeting,
|
|
86
|
+
bookmark_id: bookmark.id,
|
|
87
|
+
search_query: null,
|
|
88
|
+
},
|
|
89
|
+
},
|
|
90
|
+
};
|
|
91
|
+
|
|
92
|
+
selectors.selectRerunJobInvocationResponse.mockImplementation(
|
|
93
|
+
() => jobWithBookmark
|
|
94
|
+
);
|
|
95
|
+
|
|
96
|
+
render(
|
|
97
|
+
<MockedProvider mocks={gqlMock} addTypename={false}>
|
|
98
|
+
<Provider store={store}>
|
|
99
|
+
<JobWizardPageRerun
|
|
100
|
+
match={{
|
|
101
|
+
params: { id: '99' },
|
|
102
|
+
}}
|
|
103
|
+
/>
|
|
104
|
+
</Provider>
|
|
105
|
+
</MockedProvider>
|
|
106
|
+
);
|
|
107
|
+
|
|
108
|
+
await act(async () => {
|
|
109
|
+
fireEvent.click(screen.getByText('Target hosts and inputs'));
|
|
110
|
+
});
|
|
111
|
+
|
|
112
|
+
const hostMethodSelect = screen.getByRole('button', {
|
|
113
|
+
name: 'host method',
|
|
114
|
+
});
|
|
115
|
+
expect(hostMethodSelect.textContent).toContain('Search query');
|
|
116
|
+
|
|
117
|
+
expect(screen.queryAllByText(bookmark.query)).toHaveLength(1);
|
|
118
|
+
|
|
119
|
+
selectors.selectRerunJobInvocationResponse.mockImplementation(
|
|
120
|
+
() => jobInvocation
|
|
121
|
+
);
|
|
122
|
+
});
|
|
79
123
|
});
|
|
@@ -116,6 +116,22 @@ export const jobTemplateResponse = {
|
|
|
116
116
|
],
|
|
117
117
|
};
|
|
118
118
|
|
|
119
|
+
export const bookmarksList = [
|
|
120
|
+
{ id: 19, name: 'my hosts', query: 'name ~ myhost', controller: 'hosts' },
|
|
121
|
+
{
|
|
122
|
+
id: 23,
|
|
123
|
+
name: 'active hosts',
|
|
124
|
+
query: 'last_report > "1 hour ago"',
|
|
125
|
+
controller: 'hosts',
|
|
126
|
+
},
|
|
127
|
+
{
|
|
128
|
+
id: 31,
|
|
129
|
+
name: 'dashboard default',
|
|
130
|
+
query: 'os = centos',
|
|
131
|
+
controller: 'dashboard',
|
|
132
|
+
},
|
|
133
|
+
];
|
|
134
|
+
|
|
119
135
|
export const jobCategories = ['Services', 'Ansible Commands', 'Puppet'];
|
|
120
136
|
|
|
121
137
|
export const testSetup = (selectors, api) => {
|
|
@@ -176,6 +192,14 @@ export const testSetup = (selectors, api) => {
|
|
|
176
192
|
subtotal: 3,
|
|
177
193
|
},
|
|
178
194
|
},
|
|
195
|
+
bookmarksPF4: {
|
|
196
|
+
hosts: {
|
|
197
|
+
results: bookmarksList,
|
|
198
|
+
},
|
|
199
|
+
},
|
|
200
|
+
API: {
|
|
201
|
+
BOOKMARKS_HOSTS: { status: 'RESOLVED', results: [] },
|
|
202
|
+
},
|
|
179
203
|
});
|
|
180
204
|
return store;
|
|
181
205
|
};
|
|
@@ -1,7 +1,14 @@
|
|
|
1
|
-
import { useEffect } from 'react';
|
|
2
|
-
import { useDispatch } from 'react-redux';
|
|
1
|
+
import { useEffect, useState } from 'react';
|
|
2
|
+
import { useDispatch, useSelector } from 'react-redux';
|
|
3
3
|
import { get } from 'foremanReact/redux/API';
|
|
4
|
-
import {
|
|
4
|
+
import { getBookmarks } from 'foremanReact/components/PF4/Bookmarks/BookmarksActions';
|
|
5
|
+
import {
|
|
6
|
+
HOST_IDS,
|
|
7
|
+
REX_FEATURE,
|
|
8
|
+
hostsController,
|
|
9
|
+
hostsSearchProps,
|
|
10
|
+
} from './JobWizardConstants';
|
|
11
|
+
import { selectHostBookmarks } from './JobWizardSelectors';
|
|
5
12
|
import './JobWizard.scss';
|
|
6
13
|
|
|
7
14
|
export const useAutoFill = ({
|
|
@@ -9,11 +16,28 @@ export const useAutoFill = ({
|
|
|
9
16
|
setFills,
|
|
10
17
|
setSelectedTargets,
|
|
11
18
|
setHostsSearchQuery,
|
|
19
|
+
setSelectedBookmark,
|
|
12
20
|
setJobTemplateID,
|
|
13
21
|
setTemplateValues,
|
|
14
22
|
setAdvancedValues,
|
|
15
23
|
}) => {
|
|
16
24
|
const dispatch = useDispatch();
|
|
25
|
+
const bookmarks = useSelector(selectHostBookmarks);
|
|
26
|
+
const [pendingBookmarkId, setPendingBookmarkId] = useState(null);
|
|
27
|
+
|
|
28
|
+
useEffect(() => {
|
|
29
|
+
if (pendingBookmarkId === null || bookmarks.length === 0) return;
|
|
30
|
+
const bookmark = bookmarks.find(bm => bm.id === pendingBookmarkId);
|
|
31
|
+
if (bookmark) {
|
|
32
|
+
setSelectedBookmark({
|
|
33
|
+
id: bookmark.id,
|
|
34
|
+
name: bookmark.name,
|
|
35
|
+
query: bookmark.query,
|
|
36
|
+
});
|
|
37
|
+
setHostsSearchQuery(bookmark.query);
|
|
38
|
+
}
|
|
39
|
+
setPendingBookmarkId(null);
|
|
40
|
+
}, [bookmarks, pendingBookmarkId, setSelectedBookmark, setHostsSearchQuery]);
|
|
17
41
|
|
|
18
42
|
useEffect(() => {
|
|
19
43
|
if (Object.keys(fills).length) {
|
|
@@ -22,10 +46,12 @@ export const useAutoFill = ({
|
|
|
22
46
|
search,
|
|
23
47
|
feature,
|
|
24
48
|
template_id: templateID,
|
|
49
|
+
bookmark_id: bookmarkId,
|
|
25
50
|
...rest
|
|
26
51
|
} = { ...fills };
|
|
27
52
|
setFills({});
|
|
28
53
|
if (hostIds) {
|
|
54
|
+
setSelectedBookmark(null);
|
|
29
55
|
const hostSearch = Array.isArray(hostIds)
|
|
30
56
|
? `id = ${hostIds.join(' or id = ')}`
|
|
31
57
|
: `id = ${hostIds}`;
|
|
@@ -52,9 +78,34 @@ export const useAutoFill = ({
|
|
|
52
78
|
})
|
|
53
79
|
);
|
|
54
80
|
}
|
|
55
|
-
if (
|
|
81
|
+
if (bookmarkId) {
|
|
82
|
+
setSelectedTargets({
|
|
83
|
+
hosts: [],
|
|
84
|
+
hostCollections: [],
|
|
85
|
+
hostGroups: [],
|
|
86
|
+
});
|
|
87
|
+
const numericId = Number(bookmarkId);
|
|
88
|
+
if (bookmarks.length > 0) {
|
|
89
|
+
const bookmark = bookmarks.find(bm => bm.id === numericId);
|
|
90
|
+
if (bookmark) {
|
|
91
|
+
setSelectedBookmark({
|
|
92
|
+
id: bookmark.id,
|
|
93
|
+
name: bookmark.name,
|
|
94
|
+
query: bookmark.query,
|
|
95
|
+
});
|
|
96
|
+
setHostsSearchQuery(bookmark.query);
|
|
97
|
+
}
|
|
98
|
+
} else {
|
|
99
|
+
setPendingBookmarkId(numericId);
|
|
100
|
+
dispatch(
|
|
101
|
+
getBookmarks(hostsSearchProps.bookmarks.url, hostsController)
|
|
102
|
+
);
|
|
103
|
+
}
|
|
104
|
+
} else if ((search || search === '') && !hostIds?.length) {
|
|
56
105
|
// replace an empty string search with a dummy search query to match all hosts
|
|
57
106
|
// but only if search query was entered (based on presence of :search parameter)
|
|
107
|
+
|
|
108
|
+
setSelectedBookmark(null);
|
|
58
109
|
const hostSearch = search === '' ? "name != ''" : search;
|
|
59
110
|
setHostsSearchQuery(hostSearch);
|
|
60
111
|
}
|
|
@@ -100,9 +151,11 @@ export const useAutoFill = ({
|
|
|
100
151
|
setFills,
|
|
101
152
|
setSelectedTargets,
|
|
102
153
|
setHostsSearchQuery,
|
|
154
|
+
setSelectedBookmark,
|
|
103
155
|
setJobTemplateID,
|
|
104
156
|
setTemplateValues,
|
|
105
157
|
setAdvancedValues,
|
|
106
158
|
dispatch,
|
|
159
|
+
bookmarks,
|
|
107
160
|
]);
|
|
108
161
|
};
|
|
@@ -125,7 +125,7 @@ describe('AdvancedFields', () => {
|
|
|
125
125
|
const resourceSelectField = screen.getByLabelText(
|
|
126
126
|
'adv resource select toggle'
|
|
127
127
|
);
|
|
128
|
-
const searchField = screen.getByPlaceholderText('
|
|
128
|
+
const searchField = screen.getByPlaceholderText('Search');
|
|
129
129
|
const dateField = screen.getByLabelText('adv date datepicker');
|
|
130
130
|
const timeField = screen.getByLabelText('adv date timepicker');
|
|
131
131
|
|
|
@@ -403,6 +403,11 @@ describe('AdvancedFields', () => {
|
|
|
403
403
|
|
|
404
404
|
jest.advanceTimersByTime(10000);
|
|
405
405
|
});
|
|
406
|
-
|
|
406
|
+
const actions = newStore.getActions();
|
|
407
|
+
const resourceSearchAction = actions.filter(
|
|
408
|
+
action => action.key === 'ForemanTasksTask'
|
|
409
|
+
);
|
|
410
|
+
expect(resourceSearchAction).toHaveLength(2);
|
|
411
|
+
expect(String(resourceSearchAction[1].url)).toContain('name=some+search');
|
|
407
412
|
});
|
|
408
413
|
});
|
|
@@ -1,24 +1,47 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
2
|
import PropTypes from 'prop-types';
|
|
3
|
+
import { useSelector } from 'react-redux';
|
|
3
4
|
import SearchBar from 'foremanReact/components/SearchBar';
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
5
|
+
import { hostQuerySearchID, hostsSearchProps } from '../../JobWizardConstants';
|
|
6
|
+
import { selectHostBookmarks } from '../../JobWizardSelectors';
|
|
7
|
+
|
|
8
|
+
export const HostSearch = ({ value, setValue, onBookmarkMatch }) => {
|
|
9
|
+
const bookmarks = useSelector(selectHostBookmarks);
|
|
10
|
+
|
|
11
|
+
const handleSearchChange = search => {
|
|
12
|
+
setValue(search);
|
|
13
|
+
onBookmarkMatch(null);
|
|
14
|
+
};
|
|
15
|
+
|
|
16
|
+
const handleBookmarkSearch = query => {
|
|
17
|
+
const matched = bookmarks.find(
|
|
18
|
+
bookmark => bookmark.query && bookmark.query.trim() === query.trim()
|
|
19
|
+
);
|
|
20
|
+
if (matched) {
|
|
21
|
+
onBookmarkMatch({
|
|
22
|
+
id: matched.id,
|
|
23
|
+
name: matched.name,
|
|
24
|
+
query: matched.query,
|
|
25
|
+
});
|
|
26
|
+
} else {
|
|
27
|
+
onBookmarkMatch(null);
|
|
28
|
+
}
|
|
29
|
+
};
|
|
6
30
|
|
|
7
|
-
export const HostSearch = ({ value, setValue }) => {
|
|
8
|
-
const props = getControllerSearchProps(hostsController, hostQuerySearchID);
|
|
9
31
|
return (
|
|
10
32
|
<div className="foreman-search-field">
|
|
11
33
|
<SearchBar
|
|
12
34
|
data={{
|
|
13
|
-
...
|
|
35
|
+
...hostsSearchProps,
|
|
14
36
|
autocomplete: {
|
|
15
37
|
id: hostQuerySearchID,
|
|
16
38
|
url: '/hosts/auto_complete_search',
|
|
17
39
|
searchQuery: value,
|
|
18
40
|
},
|
|
19
41
|
}}
|
|
20
|
-
onSearch={
|
|
21
|
-
onSearchChange={
|
|
42
|
+
onSearch={handleBookmarkSearch}
|
|
43
|
+
onSearchChange={handleSearchChange}
|
|
44
|
+
bookmarksPosition="right"
|
|
22
45
|
/>
|
|
23
46
|
</div>
|
|
24
47
|
);
|
|
@@ -27,4 +50,5 @@ export const HostSearch = ({ value, setValue }) => {
|
|
|
27
50
|
HostSearch.propTypes = {
|
|
28
51
|
value: PropTypes.string.isRequired,
|
|
29
52
|
setValue: PropTypes.func.isRequired,
|
|
53
|
+
onBookmarkMatch: PropTypes.func.isRequired,
|
|
30
54
|
};
|
|
@@ -6,7 +6,12 @@ import * as api from 'foremanReact/redux/API';
|
|
|
6
6
|
import * as routerSelectors from 'foremanReact/routes/RouterSelector';
|
|
7
7
|
import { JobWizard } from '../../../JobWizard';
|
|
8
8
|
import * as selectors from '../../../JobWizardSelectors';
|
|
9
|
-
import {
|
|
9
|
+
import {
|
|
10
|
+
testSetup,
|
|
11
|
+
mockApi,
|
|
12
|
+
gqlMock,
|
|
13
|
+
bookmarksList,
|
|
14
|
+
} from '../../../__tests__/fixtures';
|
|
10
15
|
|
|
11
16
|
const store = testSetup(selectors, api);
|
|
12
17
|
mockApi(api);
|
|
@@ -183,6 +188,95 @@ describe('Hosts', () => {
|
|
|
183
188
|
expect(screen.queryAllByText('os=gnome')).toHaveLength(1);
|
|
184
189
|
});
|
|
185
190
|
|
|
191
|
+
it('submits bookmark_id when search matches a bookmark', async () => {
|
|
192
|
+
const bookmark = bookmarksList[0];
|
|
193
|
+
routerSelectors.selectRouterLocation.mockImplementation(() => ({
|
|
194
|
+
search: '',
|
|
195
|
+
}));
|
|
196
|
+
const bookmarkStore = testSetup(selectors, api);
|
|
197
|
+
mockApi(api);
|
|
198
|
+
|
|
199
|
+
render(
|
|
200
|
+
<MockedProvider mocks={gqlMock} addTypename={false}>
|
|
201
|
+
<Provider store={bookmarkStore}>
|
|
202
|
+
<JobWizard />
|
|
203
|
+
</Provider>
|
|
204
|
+
</MockedProvider>
|
|
205
|
+
);
|
|
206
|
+
|
|
207
|
+
await act(async () => {
|
|
208
|
+
fireEvent.click(screen.getByText('Target hosts and inputs'));
|
|
209
|
+
});
|
|
210
|
+
await act(async () => {
|
|
211
|
+
fireEvent.click(screen.getByRole('button', { name: 'host method' }));
|
|
212
|
+
});
|
|
213
|
+
await act(async () => {
|
|
214
|
+
fireEvent.click(screen.getByText('Search query'));
|
|
215
|
+
});
|
|
216
|
+
|
|
217
|
+
await act(async () => {
|
|
218
|
+
fireEvent.click(
|
|
219
|
+
screen.getByRole('button', { name: 'bookmarks dropdown toggle' })
|
|
220
|
+
);
|
|
221
|
+
});
|
|
222
|
+
await act(async () => {
|
|
223
|
+
fireEvent.click(screen.getByText(bookmark.name));
|
|
224
|
+
});
|
|
225
|
+
|
|
226
|
+
await act(async () => {
|
|
227
|
+
fireEvent.click(screen.getByText('Review details'));
|
|
228
|
+
});
|
|
229
|
+
await act(async () => {
|
|
230
|
+
fireEvent.click(screen.getByText('Submit'));
|
|
231
|
+
});
|
|
232
|
+
|
|
233
|
+
const submitAction = bookmarkStore
|
|
234
|
+
.getActions()
|
|
235
|
+
.find(action => action?.key === 'JOB_INVOCATION');
|
|
236
|
+
expect(submitAction).toBeDefined();
|
|
237
|
+
const { job_invocation: invocation } = submitAction.params;
|
|
238
|
+
expect(invocation.bookmark_id).toBe(bookmark.id);
|
|
239
|
+
expect(invocation.search_query).toBeNull();
|
|
240
|
+
});
|
|
241
|
+
|
|
242
|
+
it('does not submit bookmark_id when search does not match a bookmark', async () => {
|
|
243
|
+
const customQuery = 'some custom query';
|
|
244
|
+
routerSelectors.selectRouterLocation.mockImplementation(() => ({
|
|
245
|
+
search: `search=${encodeURIComponent(customQuery)}`,
|
|
246
|
+
}));
|
|
247
|
+
const customStore = testSetup(selectors, api);
|
|
248
|
+
mockApi(api);
|
|
249
|
+
|
|
250
|
+
render(
|
|
251
|
+
<MockedProvider mocks={gqlMock} addTypename={false}>
|
|
252
|
+
<Provider store={customStore}>
|
|
253
|
+
<JobWizard />
|
|
254
|
+
</Provider>
|
|
255
|
+
</MockedProvider>
|
|
256
|
+
);
|
|
257
|
+
|
|
258
|
+
await act(async () => {
|
|
259
|
+
fireEvent.click(screen.getByText('Target hosts and inputs'));
|
|
260
|
+
});
|
|
261
|
+
|
|
262
|
+
expect(screen.queryAllByText(customQuery)).toHaveLength(1);
|
|
263
|
+
|
|
264
|
+
await act(async () => {
|
|
265
|
+
fireEvent.click(screen.getByText('Review details'));
|
|
266
|
+
});
|
|
267
|
+
await act(async () => {
|
|
268
|
+
fireEvent.click(screen.getByText('Submit'));
|
|
269
|
+
});
|
|
270
|
+
|
|
271
|
+
const submitAction = customStore
|
|
272
|
+
.getActions()
|
|
273
|
+
.find(action => action?.key === 'JOB_INVOCATION');
|
|
274
|
+
expect(submitAction).toBeDefined();
|
|
275
|
+
const { job_invocation: invocation } = submitAction.params;
|
|
276
|
+
expect(invocation.bookmark_id).toBeNull();
|
|
277
|
+
expect(invocation.search_query).toBe(customQuery);
|
|
278
|
+
});
|
|
279
|
+
|
|
186
280
|
it('input fill from url', async () => {
|
|
187
281
|
const inputText = 'test text';
|
|
188
282
|
const advancedInputText = 'test adv text';
|
|
@@ -51,6 +51,7 @@ const HostsAndInputs = ({
|
|
|
51
51
|
setSelected,
|
|
52
52
|
hostsSearchQuery,
|
|
53
53
|
setHostsSearchQuery,
|
|
54
|
+
setSelectedBookmark,
|
|
54
55
|
}) => {
|
|
55
56
|
const defaultHostMethod = hostsSearchQuery.length
|
|
56
57
|
? hostMethods.searchQuery
|
|
@@ -132,6 +133,7 @@ const HostsAndInputs = ({
|
|
|
132
133
|
|
|
133
134
|
const clearSearch = () => {
|
|
134
135
|
setHostsSearchQuery('');
|
|
136
|
+
setSelectedBookmark(null);
|
|
135
137
|
};
|
|
136
138
|
const [errorText, setErrorText] = useState(
|
|
137
139
|
__('Please select at least one host')
|
|
@@ -156,6 +158,7 @@ const HostsAndInputs = ({
|
|
|
156
158
|
className="target-method-select"
|
|
157
159
|
toggleIcon={<FilterIcon />}
|
|
158
160
|
fieldId="host_methods"
|
|
161
|
+
toggleAriaLabel={__('host method')}
|
|
159
162
|
options={Object.values(hostMethods).filter(method => {
|
|
160
163
|
if (method === hostMethods.hostCollections && !withKatello) {
|
|
161
164
|
return false;
|
|
@@ -186,6 +189,7 @@ const HostsAndInputs = ({
|
|
|
186
189
|
<HostSearch
|
|
187
190
|
setValue={setHostsSearchQuery}
|
|
188
191
|
value={hostsSearchQuery}
|
|
192
|
+
onBookmarkMatch={setSelectedBookmark}
|
|
189
193
|
/>
|
|
190
194
|
)}
|
|
191
195
|
{hostMethod === hostMethods.hosts && (
|
|
@@ -286,6 +290,7 @@ HostsAndInputs.propTypes = {
|
|
|
286
290
|
setSelected: PropTypes.func.isRequired,
|
|
287
291
|
hostsSearchQuery: PropTypes.string.isRequired,
|
|
288
292
|
setHostsSearchQuery: PropTypes.func.isRequired,
|
|
293
|
+
setSelectedBookmark: PropTypes.func.isRequired,
|
|
289
294
|
};
|
|
290
295
|
|
|
291
296
|
export default HostsAndInputs;
|
data/webpack/JobWizard/submit.js
CHANGED
|
@@ -2,6 +2,14 @@ import { post } from 'foremanReact/redux/API';
|
|
|
2
2
|
import { repeatTypes, JOB_INVOCATION } from './JobWizardConstants';
|
|
3
3
|
import { buildHostQuery } from './steps/HostsAndInputs/buildHostQuery';
|
|
4
4
|
|
|
5
|
+
const hasExplicitTargets = selectedTargets =>
|
|
6
|
+
selectedTargets.hosts.length > 0 ||
|
|
7
|
+
selectedTargets.hostCollections.length > 0 ||
|
|
8
|
+
selectedTargets.hostGroups.length > 0;
|
|
9
|
+
|
|
10
|
+
const shouldSendBookmark = (selectedBookmark, selectedTargets) =>
|
|
11
|
+
selectedBookmark && !hasExplicitTargets(selectedTargets);
|
|
12
|
+
|
|
5
13
|
export const submit = ({
|
|
6
14
|
jobTemplateID,
|
|
7
15
|
templateValues,
|
|
@@ -9,6 +17,7 @@ export const submit = ({
|
|
|
9
17
|
scheduleValue,
|
|
10
18
|
selectedTargets,
|
|
11
19
|
hostsSearchQuery,
|
|
20
|
+
selectedBookmark,
|
|
12
21
|
location,
|
|
13
22
|
organization,
|
|
14
23
|
feature,
|
|
@@ -110,8 +119,12 @@ export const submit = ({
|
|
|
110
119
|
concurrency_control: {
|
|
111
120
|
concurrency_level: concurrencyLevel,
|
|
112
121
|
},
|
|
113
|
-
bookmark_id:
|
|
114
|
-
|
|
122
|
+
bookmark_id: shouldSendBookmark(selectedBookmark, selectedTargets)
|
|
123
|
+
? selectedBookmark.id
|
|
124
|
+
: null,
|
|
125
|
+
search_query: shouldSendBookmark(selectedBookmark, selectedTargets)
|
|
126
|
+
? null
|
|
127
|
+
: buildHostQuery(selectedTargets, hostsSearchQuery),
|
|
115
128
|
description_format: description,
|
|
116
129
|
execution_timeout_interval: timeoutToKill,
|
|
117
130
|
feature,
|
|
@@ -4,9 +4,8 @@ import PropTypes from 'prop-types';
|
|
|
4
4
|
|
|
5
5
|
import { translate as __ } from 'foremanReact/common/I18n';
|
|
6
6
|
import LabelIcon from 'foremanReact/components/common/LabelIcon';
|
|
7
|
-
import { Alert } from 'patternfly-react';
|
|
8
|
-
|
|
9
7
|
import {
|
|
8
|
+
Alert,
|
|
10
9
|
FormGroup,
|
|
11
10
|
FormSelectOption,
|
|
12
11
|
FormSelect,
|
|
@@ -26,11 +25,15 @@ const options = (value = '') => {
|
|
|
26
25
|
};
|
|
27
26
|
|
|
28
27
|
const pullWarning = (
|
|
29
|
-
<Alert
|
|
30
|
-
|
|
28
|
+
<Alert
|
|
29
|
+
ouiaId="overrideAlert"
|
|
30
|
+
variant="info"
|
|
31
|
+
isInline
|
|
32
|
+
title={__(
|
|
31
33
|
'Please make sure that the Smart Proxy is configured correctly for the Pull provider.'
|
|
32
34
|
)}
|
|
33
|
-
|
|
35
|
+
style={{ marginTop: '10px' }}
|
|
36
|
+
/>
|
|
34
37
|
);
|
|
35
38
|
|
|
36
39
|
function showPullWarning(valueFromParam, value) {
|
|
@@ -14,6 +14,7 @@ exports[`TargetingHostsPage renders 1`] = `
|
|
|
14
14
|
md={6}
|
|
15
15
|
>
|
|
16
16
|
<SearchBar
|
|
17
|
+
bookmarksPosition="left"
|
|
17
18
|
data={
|
|
18
19
|
Object {
|
|
19
20
|
"autocomplete": Object {
|
|
@@ -31,9 +32,12 @@ exports[`TargetingHostsPage renders 1`] = `
|
|
|
31
32
|
"controller": "hosts",
|
|
32
33
|
}
|
|
33
34
|
}
|
|
35
|
+
initialQuery=""
|
|
36
|
+
name={null}
|
|
34
37
|
onBookmarkClick={[Function]}
|
|
35
|
-
onChange={[Function]}
|
|
36
38
|
onSearch={[Function]}
|
|
39
|
+
onSearchChange={[Function]}
|
|
40
|
+
restrictedSearchQuery={[Function]}
|
|
37
41
|
/>
|
|
38
42
|
</Col>
|
|
39
43
|
</Row>
|
metadata
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: foreman_remote_execution
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 16.
|
|
4
|
+
version: 16.6.4
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Foreman Remote Execution team
|
|
8
8
|
bindir: bin
|
|
9
9
|
cert_chain: []
|
|
10
|
-
date: 2026-
|
|
10
|
+
date: 2026-06-02 00:00:00.000000000 Z
|
|
11
11
|
dependencies:
|
|
12
12
|
- !ruby/object:Gem::Dependency
|
|
13
13
|
name: deface
|
|
@@ -37,34 +37,6 @@ dependencies:
|
|
|
37
37
|
- - ">="
|
|
38
38
|
- !ruby/object:Gem::Version
|
|
39
39
|
version: 8.3.0
|
|
40
|
-
- !ruby/object:Gem::Dependency
|
|
41
|
-
name: factory_bot_rails
|
|
42
|
-
requirement: !ruby/object:Gem::Requirement
|
|
43
|
-
requirements:
|
|
44
|
-
- - "~>"
|
|
45
|
-
- !ruby/object:Gem::Version
|
|
46
|
-
version: 4.8.0
|
|
47
|
-
type: :development
|
|
48
|
-
prerelease: false
|
|
49
|
-
version_requirements: !ruby/object:Gem::Requirement
|
|
50
|
-
requirements:
|
|
51
|
-
- - "~>"
|
|
52
|
-
- !ruby/object:Gem::Version
|
|
53
|
-
version: 4.8.0
|
|
54
|
-
- !ruby/object:Gem::Dependency
|
|
55
|
-
name: rdoc
|
|
56
|
-
requirement: !ruby/object:Gem::Requirement
|
|
57
|
-
requirements:
|
|
58
|
-
- - ">="
|
|
59
|
-
- !ruby/object:Gem::Version
|
|
60
|
-
version: '0'
|
|
61
|
-
type: :development
|
|
62
|
-
prerelease: false
|
|
63
|
-
version_requirements: !ruby/object:Gem::Requirement
|
|
64
|
-
requirements:
|
|
65
|
-
- - ">="
|
|
66
|
-
- !ruby/object:Gem::Version
|
|
67
|
-
version: '0'
|
|
68
40
|
description: A plugin bringing remote execution to the Foreman, completing the config
|
|
69
41
|
management functionality with remote management functionality.
|
|
70
42
|
email:
|
|
@@ -448,7 +420,6 @@ files:
|
|
|
448
420
|
- webpack/JobWizard/steps/AdvancedFields/DescriptionField.js
|
|
449
421
|
- webpack/JobWizard/steps/AdvancedFields/Fields.js
|
|
450
422
|
- webpack/JobWizard/steps/AdvancedFields/__tests__/AdvancedFields.test.js
|
|
451
|
-
- webpack/JobWizard/steps/AdvancedFields/__tests__/__snapshots__/AdvancedFields.test.js.snap
|
|
452
423
|
- webpack/JobWizard/steps/CategoryAndTemplate/CategoryAndTemplate.js
|
|
453
424
|
- webpack/JobWizard/steps/CategoryAndTemplate/CategoryAndTemplate.test.js
|
|
454
425
|
- webpack/JobWizard/steps/CategoryAndTemplate/index.js
|
|
@@ -503,7 +474,6 @@ files:
|
|
|
503
474
|
- webpack/__mocks__/foremanReact/components/Head/index.js
|
|
504
475
|
- webpack/__mocks__/foremanReact/components/HostDetails/DetailsCard/DefaultLoaderEmptyState.js
|
|
505
476
|
- webpack/__mocks__/foremanReact/components/Pagination.js
|
|
506
|
-
- webpack/__mocks__/foremanReact/components/SearchBar.js
|
|
507
477
|
- webpack/__mocks__/foremanReact/components/ToastsList/index.js
|
|
508
478
|
- webpack/__mocks__/foremanReact/components/common/ActionButtons/ActionButtons.js
|
|
509
479
|
- webpack/__mocks__/foremanReact/constants.js
|
|
@@ -589,7 +559,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
589
559
|
- !ruby/object:Gem::Version
|
|
590
560
|
version: '0'
|
|
591
561
|
requirements: []
|
|
592
|
-
rubygems_version: 4.0.
|
|
562
|
+
rubygems_version: 4.0.10
|
|
593
563
|
specification_version: 4
|
|
594
564
|
summary: A plugin bringing remote execution to the Foreman, completing the config
|
|
595
565
|
management functionality with remote management functionality.
|
data/webpack/JobWizard/steps/AdvancedFields/__tests__/__snapshots__/AdvancedFields.test.js.snap
DELETED
|
@@ -1,90 +0,0 @@
|
|
|
1
|
-
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
|
2
|
-
|
|
3
|
-
exports[`AdvancedFields search resources action: resource search 1`] = `
|
|
4
|
-
Array [
|
|
5
|
-
Object {
|
|
6
|
-
"key": "JOB_CATEGORIES",
|
|
7
|
-
"type": "get",
|
|
8
|
-
"url": "/ui_job_wizard/categories",
|
|
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
|
-
Object {
|
|
19
|
-
"key": "JOB_TEMPLATES",
|
|
20
|
-
"type": "get",
|
|
21
|
-
"url": URI {
|
|
22
|
-
"_deferred_build": true,
|
|
23
|
-
"_parts": Object {
|
|
24
|
-
"duplicateQueryParameters": false,
|
|
25
|
-
"escapeQuerySpace": true,
|
|
26
|
-
"fragment": null,
|
|
27
|
-
"hostname": null,
|
|
28
|
-
"password": null,
|
|
29
|
-
"path": "foreman/api/v2/job_templates",
|
|
30
|
-
"port": null,
|
|
31
|
-
"preventInvalidHostname": false,
|
|
32
|
-
"protocol": null,
|
|
33
|
-
"query": "search=job_category%3D%22Ansible+Commands%22&per_page=all",
|
|
34
|
-
"urn": null,
|
|
35
|
-
"username": null,
|
|
36
|
-
},
|
|
37
|
-
"_string": "",
|
|
38
|
-
},
|
|
39
|
-
},
|
|
40
|
-
Object {
|
|
41
|
-
"key": "JOB_TEMPLATE",
|
|
42
|
-
"type": "get",
|
|
43
|
-
"url": "/ui_job_wizard/template/178",
|
|
44
|
-
},
|
|
45
|
-
Object {
|
|
46
|
-
"key": "ForemanTasksTask",
|
|
47
|
-
"type": "get",
|
|
48
|
-
"url": URI {
|
|
49
|
-
"_deferred_build": true,
|
|
50
|
-
"_parts": Object {
|
|
51
|
-
"duplicateQueryParameters": false,
|
|
52
|
-
"escapeQuerySpace": true,
|
|
53
|
-
"fragment": null,
|
|
54
|
-
"hostname": null,
|
|
55
|
-
"password": null,
|
|
56
|
-
"path": "/ui_job_wizard/resources",
|
|
57
|
-
"port": null,
|
|
58
|
-
"preventInvalidHostname": false,
|
|
59
|
-
"protocol": null,
|
|
60
|
-
"query": "resource=ForemanTasks%3A%3ATask",
|
|
61
|
-
"urn": null,
|
|
62
|
-
"username": null,
|
|
63
|
-
},
|
|
64
|
-
"_string": "",
|
|
65
|
-
},
|
|
66
|
-
},
|
|
67
|
-
Object {
|
|
68
|
-
"key": "ForemanTasksTask",
|
|
69
|
-
"type": "get",
|
|
70
|
-
"url": URI {
|
|
71
|
-
"_deferred_build": true,
|
|
72
|
-
"_parts": Object {
|
|
73
|
-
"duplicateQueryParameters": false,
|
|
74
|
-
"escapeQuerySpace": true,
|
|
75
|
-
"fragment": null,
|
|
76
|
-
"hostname": null,
|
|
77
|
-
"password": null,
|
|
78
|
-
"path": "/ui_job_wizard/resources",
|
|
79
|
-
"port": null,
|
|
80
|
-
"preventInvalidHostname": false,
|
|
81
|
-
"protocol": null,
|
|
82
|
-
"query": "resource=ForemanTasks%3A%3ATask&name=some+search",
|
|
83
|
-
"urn": null,
|
|
84
|
-
"username": null,
|
|
85
|
-
},
|
|
86
|
-
"_string": "",
|
|
87
|
-
},
|
|
88
|
-
},
|
|
89
|
-
]
|
|
90
|
-
`;
|
|
@@ -1,19 +0,0 @@
|
|
|
1
|
-
import React from 'react';
|
|
2
|
-
import PropTypes from 'prop-types';
|
|
3
|
-
|
|
4
|
-
const SearchBar = ({ onChange }) => (
|
|
5
|
-
<input
|
|
6
|
-
className="foreman-search"
|
|
7
|
-
onChange={onChange}
|
|
8
|
-
placeholder="Filter..."
|
|
9
|
-
/>
|
|
10
|
-
);
|
|
11
|
-
export default SearchBar;
|
|
12
|
-
|
|
13
|
-
SearchBar.propTypes = {
|
|
14
|
-
onChange: PropTypes.func,
|
|
15
|
-
};
|
|
16
|
-
|
|
17
|
-
SearchBar.defaultProps = {
|
|
18
|
-
onChange: () => null,
|
|
19
|
-
};
|