foreman_remote_execution 3.3.4 → 4.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.github/workflows/ci.yml +1 -1
- data/app/controllers/api/v2/job_invocations_controller.rb +1 -0
- data/app/controllers/foreman_remote_execution/concerns/api/v2/subnets_controller_extensions.rb +21 -0
- data/app/controllers/job_invocations_controller.rb +22 -8
- data/app/helpers/job_invocations_helper.rb +3 -2
- data/app/lib/actions/remote_execution/run_host_job.rb +1 -1
- data/app/lib/actions/remote_execution/run_hosts_job.rb +4 -3
- data/app/lib/foreman_remote_execution/renderer/scope/input.rb +35 -0
- data/app/models/concerns/api/v2/interfaces_controller_extensions.rb +13 -0
- data/app/models/concerns/foreman_remote_execution/orchestration/ssh.rb +11 -4
- data/app/models/job_invocation.rb +11 -4
- data/app/models/job_invocation_composer.rb +2 -2
- data/app/models/remote_execution_provider.rb +2 -2
- data/app/models/setting/remote_execution.rb +2 -2
- data/app/models/ssh_execution_provider.rb +1 -1
- data/app/views/api/v2/interfaces/execution_flag.json.rabl +1 -0
- data/app/views/api/v2/job_invocations/base.json.rabl +1 -0
- data/app/views/api/v2/job_invocations/main.json.rabl +1 -1
- data/app/views/api/v2/subnets/remote_execution_proxies.json.rabl +3 -0
- data/app/views/job_invocations/_form.html.erb +1 -1
- data/app/views/job_invocations/_tab_hosts.html.erb +1 -20
- data/app/views/job_invocations/_tab_overview.html.erb +13 -1
- data/app/views/job_invocations/show.html.erb +9 -0
- data/app/views/job_invocations/show.js.erb +5 -0
- data/app/views/job_invocations/show.json.erb +2 -1
- data/db/migrate/20200623073022_rename_sudo_password_to_effective_user_password.rb +34 -0
- data/db/seeds.d/20-permissions.rb +9 -0
- data/lib/foreman_remote_execution/engine.rb +19 -1
- data/lib/foreman_remote_execution/version.rb +1 -1
- data/test/functional/api/v2/job_invocations_controller_test.rb +65 -2
- data/test/functional/job_invocations_controller_test.rb +71 -0
- data/test/models/orchestration/ssh_test.rb +1 -1
- data/test/support/remote_execution_helper.rb +5 -0
- data/test/unit/actions/run_host_job_test.rb +3 -3
- data/test/unit/actions/run_hosts_job_test.rb +2 -2
- data/test/unit/job_invocation_composer_test.rb +5 -5
- data/test/unit/remote_execution_provider_test.rb +6 -6
- data/webpack/__mocks__/foremanReact/components/Pagination/PaginationWrapper.js +2 -0
- data/webpack/__mocks__/foremanReact/components/SearchBar.js +2 -0
- data/webpack/__mocks__/foremanReact/constants.js +21 -0
- data/webpack/__mocks__/foremanReact/redux/API/APISelectors.js +2 -0
- data/webpack/__mocks__/foremanReact/redux/middlewares/IntervalMiddleware/IntervalSelectors.js +1 -0
- data/webpack/react_app/components/TargetingHosts/TargetingHosts.js +21 -15
- data/webpack/react_app/components/TargetingHosts/TargetingHostsHelpers.js +10 -0
- data/webpack/react_app/components/TargetingHosts/TargetingHostsPage.js +62 -0
- data/webpack/react_app/components/TargetingHosts/TargetingHostsPage.scss +6 -0
- data/webpack/react_app/components/TargetingHosts/TargetingHostsSelectors.js +10 -2
- data/webpack/react_app/components/TargetingHosts/__tests__/TargetingHostsPage.test.js +9 -0
- data/webpack/react_app/components/TargetingHosts/__tests__/TargetingHostsSelectors.test.js +26 -0
- data/webpack/react_app/components/TargetingHosts/__tests__/__snapshots__/TargetingHosts.test.js.snap +16 -1
- data/webpack/react_app/components/TargetingHosts/__tests__/__snapshots__/TargetingHostsPage.test.js.snap +68 -0
- data/webpack/react_app/components/TargetingHosts/__tests__/__snapshots__/TargetingHostsSelectors.test.js.snap +11 -0
- data/webpack/react_app/components/TargetingHosts/__tests__/fixtures.js +35 -19
- data/webpack/react_app/components/TargetingHosts/index.js +73 -13
- metadata +22 -3
- data/webpack/react_app/components/TargetingHosts/TargetingHostsActions.js +0 -8
@@ -0,0 +1 @@
|
|
1
|
+
export const selectDoesIntervalExist = () => false;
|
@@ -5,8 +5,8 @@ import { LoadingState, Alert } from 'patternfly-react';
|
|
5
5
|
import { STATUS } from 'foremanReact/constants';
|
6
6
|
import HostItem from './components/HostItem';
|
7
7
|
|
8
|
-
const TargetingHosts = ({
|
9
|
-
if (
|
8
|
+
const TargetingHosts = ({ apiStatus, items }) => {
|
9
|
+
if (apiStatus === STATUS.ERROR) {
|
10
10
|
return (
|
11
11
|
<Alert type="error">
|
12
12
|
{__(
|
@@ -16,8 +16,24 @@ const TargetingHosts = ({ status, items }) => {
|
|
16
16
|
);
|
17
17
|
}
|
18
18
|
|
19
|
+
const tableBodyRows = items.length ? (
|
20
|
+
items.map(({ name, link, status, actions }) => (
|
21
|
+
<HostItem
|
22
|
+
key={name}
|
23
|
+
name={name}
|
24
|
+
link={link}
|
25
|
+
status={status}
|
26
|
+
actions={actions}
|
27
|
+
/>
|
28
|
+
))
|
29
|
+
) : (
|
30
|
+
<tr>
|
31
|
+
<td colSpan="3">{__('No hosts found.')}</td>
|
32
|
+
</tr>
|
33
|
+
);
|
34
|
+
|
19
35
|
return (
|
20
|
-
<LoadingState loading={!items.length}>
|
36
|
+
<LoadingState loading={!items.length && apiStatus === STATUS.PENDING}>
|
21
37
|
<div>
|
22
38
|
<table className="table table-bordered table-striped table-hover">
|
23
39
|
<thead>
|
@@ -27,17 +43,7 @@ const TargetingHosts = ({ status, items }) => {
|
|
27
43
|
<th>{__('Actions')}</th>
|
28
44
|
</tr>
|
29
45
|
</thead>
|
30
|
-
<tbody>
|
31
|
-
{items.map(host => (
|
32
|
-
<HostItem
|
33
|
-
key={host.name}
|
34
|
-
name={host.name}
|
35
|
-
link={host.link}
|
36
|
-
status={host.status}
|
37
|
-
actions={host.actions}
|
38
|
-
/>
|
39
|
-
))}
|
40
|
-
</tbody>
|
46
|
+
<tbody>{tableBodyRows}</tbody>
|
41
47
|
</table>
|
42
48
|
</div>
|
43
49
|
</LoadingState>
|
@@ -45,7 +51,7 @@ const TargetingHosts = ({ status, items }) => {
|
|
45
51
|
};
|
46
52
|
|
47
53
|
TargetingHosts.propTypes = {
|
48
|
-
|
54
|
+
apiStatus: PropTypes.string.isRequired,
|
49
55
|
items: PropTypes.array.isRequired,
|
50
56
|
};
|
51
57
|
|
@@ -0,0 +1,10 @@
|
|
1
|
+
import { getURI } from 'foremanReact/common/urlHelpers';
|
2
|
+
|
3
|
+
export const getApiUrl = (searchQuery, pagination) => {
|
4
|
+
const baseUrl = getURI()
|
5
|
+
.search('')
|
6
|
+
.addQuery('page', pagination.page)
|
7
|
+
.addQuery('per_page', pagination.perPage);
|
8
|
+
|
9
|
+
return searchQuery ? baseUrl.addQuery('search', searchQuery) : baseUrl;
|
10
|
+
};
|
@@ -0,0 +1,62 @@
|
|
1
|
+
import React from 'react';
|
2
|
+
import PropTypes from 'prop-types';
|
3
|
+
import { Grid } from 'patternfly-react';
|
4
|
+
|
5
|
+
import SearchBar from 'foremanReact/components/SearchBar';
|
6
|
+
import Pagination from 'foremanReact/components/Pagination/PaginationWrapper';
|
7
|
+
import { getControllerSearchProps } from 'foremanReact/constants';
|
8
|
+
|
9
|
+
import TargetingHosts from './TargetingHosts';
|
10
|
+
import './TargetingHostsPage.scss';
|
11
|
+
|
12
|
+
const TargetingHostsPage = ({
|
13
|
+
handleSearch,
|
14
|
+
searchQuery,
|
15
|
+
apiStatus,
|
16
|
+
items,
|
17
|
+
totalHosts,
|
18
|
+
pagination,
|
19
|
+
handlePagination,
|
20
|
+
}) => (
|
21
|
+
<div id="targeting_hosts">
|
22
|
+
<Grid.Row>
|
23
|
+
<Grid.Col md={6} className="title_filter">
|
24
|
+
<SearchBar
|
25
|
+
onSearch={query => handleSearch(query)}
|
26
|
+
data={{
|
27
|
+
...getControllerSearchProps('hosts'),
|
28
|
+
autocomplete: {
|
29
|
+
id: 'targeting_hosts_search',
|
30
|
+
searchQuery,
|
31
|
+
url: '/hosts/auto_complete_search',
|
32
|
+
useKeyShortcuts: true,
|
33
|
+
},
|
34
|
+
bookmarks: {},
|
35
|
+
}}
|
36
|
+
/>
|
37
|
+
</Grid.Col>
|
38
|
+
</Grid.Row>
|
39
|
+
<br />
|
40
|
+
<TargetingHosts apiStatus={apiStatus} items={items} />
|
41
|
+
<Pagination
|
42
|
+
viewType="list"
|
43
|
+
itemCount={totalHosts}
|
44
|
+
pagination={pagination}
|
45
|
+
onChange={args => handlePagination(args)}
|
46
|
+
dropdownButtonId="targeting-hosts-pagination-dropdown"
|
47
|
+
className="targeting-hosts-pagination"
|
48
|
+
/>
|
49
|
+
</div>
|
50
|
+
);
|
51
|
+
|
52
|
+
TargetingHostsPage.propTypes = {
|
53
|
+
handleSearch: PropTypes.func.isRequired,
|
54
|
+
searchQuery: PropTypes.string.isRequired,
|
55
|
+
apiStatus: PropTypes.string.isRequired,
|
56
|
+
items: PropTypes.array.isRequired,
|
57
|
+
totalHosts: PropTypes.number.isRequired,
|
58
|
+
pagination: PropTypes.object.isRequired,
|
59
|
+
handlePagination: PropTypes.func.isRequired,
|
60
|
+
};
|
61
|
+
|
62
|
+
export default TargetingHostsPage;
|
@@ -2,11 +2,19 @@ import {
|
|
2
2
|
selectAPIStatus,
|
3
3
|
selectAPIResponse,
|
4
4
|
} from 'foremanReact/redux/API/APISelectors';
|
5
|
+
import { selectDoesIntervalExist } from 'foremanReact/redux/middlewares/IntervalMiddleware/IntervalSelectors';
|
6
|
+
|
5
7
|
import { TARGETING_HOSTS } from './TargetingHostsConsts';
|
6
8
|
|
7
9
|
export const selectItems = state =>
|
8
10
|
selectAPIResponse(state, TARGETING_HOSTS).hosts || [];
|
9
11
|
|
10
12
|
export const selectAutoRefresh = state =>
|
11
|
-
selectAPIResponse(state, TARGETING_HOSTS).autoRefresh;
|
12
|
-
|
13
|
+
selectAPIResponse(state, TARGETING_HOSTS).autoRefresh || '';
|
14
|
+
|
15
|
+
export const selectApiStatus = state => selectAPIStatus(state, TARGETING_HOSTS);
|
16
|
+
export const selectTotalHosts = state =>
|
17
|
+
selectAPIResponse(state, TARGETING_HOSTS).total_hosts || 0;
|
18
|
+
|
19
|
+
export const selectIntervalExists = state =>
|
20
|
+
selectDoesIntervalExist(state, TARGETING_HOSTS);
|
@@ -0,0 +1,9 @@
|
|
1
|
+
import { testComponentSnapshotsWithFixtures } from '@theforeman/test';
|
2
|
+
import TargetingHostsPage from '../TargetingHostsPage';
|
3
|
+
import { TargetingHostsPageFixtures } from './fixtures';
|
4
|
+
|
5
|
+
describe('TargetingHostsPage', () =>
|
6
|
+
testComponentSnapshotsWithFixtures(
|
7
|
+
TargetingHostsPage,
|
8
|
+
TargetingHostsPageFixtures
|
9
|
+
));
|
@@ -0,0 +1,26 @@
|
|
1
|
+
import { testSelectorsSnapshotWithFixtures } from '@theforeman/test';
|
2
|
+
|
3
|
+
import {
|
4
|
+
selectItems,
|
5
|
+
selectAutoRefresh,
|
6
|
+
selectApiStatus,
|
7
|
+
selectTotalHosts,
|
8
|
+
selectIntervalExists,
|
9
|
+
} from '../TargetingHostsSelectors';
|
10
|
+
|
11
|
+
const state = {
|
12
|
+
hosts: [],
|
13
|
+
autoRefresh: 'true',
|
14
|
+
total_hosts: 0,
|
15
|
+
};
|
16
|
+
|
17
|
+
const fixtures = {
|
18
|
+
'should return hosts': () => selectItems(state),
|
19
|
+
'should return autoRefresh': () => selectAutoRefresh(state),
|
20
|
+
'should return apiStatus': () => selectApiStatus(state),
|
21
|
+
'should return totalHosts': () => selectTotalHosts(state),
|
22
|
+
'should return intervalExists': () => selectIntervalExists(state),
|
23
|
+
};
|
24
|
+
|
25
|
+
describe('TargetingHostsSelectors', () =>
|
26
|
+
testSelectorsSnapshotWithFixtures(fixtures));
|
data/webpack/react_app/components/TargetingHosts/__tests__/__snapshots__/TargetingHosts.test.js.snap
CHANGED
@@ -33,6 +33,13 @@ exports[`TargetingHosts renders 1`] = `
|
|
33
33
|
name="host"
|
34
34
|
status="success"
|
35
35
|
/>
|
36
|
+
<HostItem
|
37
|
+
actions={Array []}
|
38
|
+
key="host2"
|
39
|
+
link="/link2"
|
40
|
+
name="host2"
|
41
|
+
status="success"
|
42
|
+
/>
|
36
43
|
</tbody>
|
37
44
|
</table>
|
38
45
|
</div>
|
@@ -74,7 +81,15 @@ exports[`TargetingHosts renders with loading 1`] = `
|
|
74
81
|
</th>
|
75
82
|
</tr>
|
76
83
|
</thead>
|
77
|
-
<tbody
|
84
|
+
<tbody>
|
85
|
+
<tr>
|
86
|
+
<td
|
87
|
+
colSpan="3"
|
88
|
+
>
|
89
|
+
No hosts found.
|
90
|
+
</td>
|
91
|
+
</tr>
|
92
|
+
</tbody>
|
78
93
|
</table>
|
79
94
|
</div>
|
80
95
|
</LoadingState>
|
@@ -0,0 +1,68 @@
|
|
1
|
+
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
2
|
+
|
3
|
+
exports[`TargetingHostsPage renders 1`] = `
|
4
|
+
<div
|
5
|
+
id="targeting_hosts"
|
6
|
+
>
|
7
|
+
<Row
|
8
|
+
bsClass="row"
|
9
|
+
componentClass="div"
|
10
|
+
>
|
11
|
+
<Col
|
12
|
+
bsClass="col"
|
13
|
+
className="title_filter"
|
14
|
+
componentClass="div"
|
15
|
+
md={6}
|
16
|
+
>
|
17
|
+
<SearchBar
|
18
|
+
data={
|
19
|
+
Object {
|
20
|
+
"autocomplete": Object {
|
21
|
+
"id": "targeting_hosts_search",
|
22
|
+
"searchQuery": "",
|
23
|
+
"url": "/hosts/auto_complete_search",
|
24
|
+
"useKeyShortcuts": true,
|
25
|
+
},
|
26
|
+
"bookmarks": Object {},
|
27
|
+
"controller": "hosts",
|
28
|
+
}
|
29
|
+
}
|
30
|
+
onSearch={[Function]}
|
31
|
+
/>
|
32
|
+
</Col>
|
33
|
+
</Row>
|
34
|
+
<br />
|
35
|
+
<TargetingHosts
|
36
|
+
apiStatus="RESOLVED"
|
37
|
+
items={
|
38
|
+
Array [
|
39
|
+
Object {
|
40
|
+
"actions": Array [],
|
41
|
+
"link": "/link",
|
42
|
+
"name": "host",
|
43
|
+
"status": "success",
|
44
|
+
},
|
45
|
+
Object {
|
46
|
+
"actions": Array [],
|
47
|
+
"link": "/link2",
|
48
|
+
"name": "host2",
|
49
|
+
"status": "success",
|
50
|
+
},
|
51
|
+
]
|
52
|
+
}
|
53
|
+
/>
|
54
|
+
<PaginationWrapper
|
55
|
+
className="targeting-hosts-pagination"
|
56
|
+
dropdownButtonId="targeting-hosts-pagination-dropdown"
|
57
|
+
itemCount={1}
|
58
|
+
onChange={[Function]}
|
59
|
+
pagination={
|
60
|
+
Object {
|
61
|
+
"page": 1,
|
62
|
+
"perPage": 20,
|
63
|
+
}
|
64
|
+
}
|
65
|
+
viewType="list"
|
66
|
+
/>
|
67
|
+
</div>
|
68
|
+
`;
|
@@ -0,0 +1,11 @@
|
|
1
|
+
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
2
|
+
|
3
|
+
exports[`TargetingHostsSelectors should return apiStatus 1`] = `"RESOLVED"`;
|
4
|
+
|
5
|
+
exports[`TargetingHostsSelectors should return autoRefresh 1`] = `"true"`;
|
6
|
+
|
7
|
+
exports[`TargetingHostsSelectors should return hosts 1`] = `Array []`;
|
8
|
+
|
9
|
+
exports[`TargetingHostsSelectors should return intervalExists 1`] = `false`;
|
10
|
+
|
11
|
+
exports[`TargetingHostsSelectors should return totalHosts 1`] = `0`;
|
@@ -1,3 +1,18 @@
|
|
1
|
+
const items = [
|
2
|
+
{
|
3
|
+
name: 'host',
|
4
|
+
link: '/link',
|
5
|
+
status: 'success',
|
6
|
+
actions: [],
|
7
|
+
},
|
8
|
+
{
|
9
|
+
name: 'host2',
|
10
|
+
link: '/link2',
|
11
|
+
status: 'success',
|
12
|
+
actions: [],
|
13
|
+
},
|
14
|
+
];
|
15
|
+
|
1
16
|
export const HostItemFixtures = {
|
2
17
|
renders: {
|
3
18
|
name: 'Host1',
|
@@ -15,29 +30,30 @@ export const HostStatusFixtures = {
|
|
15
30
|
|
16
31
|
export const TargetingHostsFixtures = {
|
17
32
|
renders: {
|
18
|
-
|
19
|
-
items
|
20
|
-
{
|
21
|
-
name: 'host',
|
22
|
-
link: '/link',
|
23
|
-
status: 'success',
|
24
|
-
actions: [],
|
25
|
-
},
|
26
|
-
],
|
33
|
+
apiStatus: 'RESOLVED',
|
34
|
+
items,
|
27
35
|
},
|
28
36
|
'renders with error': {
|
29
|
-
|
30
|
-
items
|
31
|
-
{
|
32
|
-
name: 'host',
|
33
|
-
link: '/link',
|
34
|
-
status: 'success',
|
35
|
-
actions: [],
|
36
|
-
},
|
37
|
-
],
|
37
|
+
apiStatus: 'ERROR',
|
38
|
+
items,
|
38
39
|
},
|
39
40
|
'renders with loading': {
|
40
|
-
|
41
|
+
apiStatus: 'PENDING',
|
41
42
|
items: [],
|
42
43
|
},
|
43
44
|
};
|
45
|
+
|
46
|
+
export const TargetingHostsPageFixtures = {
|
47
|
+
renders: {
|
48
|
+
handleSearch: () => {},
|
49
|
+
searchQuery: '',
|
50
|
+
apiStatus: 'RESOLVED',
|
51
|
+
items,
|
52
|
+
totalHosts: 1,
|
53
|
+
pagination: {
|
54
|
+
page: 1,
|
55
|
+
perPage: 20,
|
56
|
+
},
|
57
|
+
handlePagination: () => {},
|
58
|
+
},
|
59
|
+
};
|
@@ -1,37 +1,97 @@
|
|
1
|
-
import React, { useEffect } from 'react';
|
1
|
+
import React, { useEffect, useState } from 'react';
|
2
2
|
import { useSelector, useDispatch } from 'react-redux';
|
3
|
-
|
4
|
-
import
|
3
|
+
|
4
|
+
import { get } from 'foremanReact/redux/API';
|
5
|
+
import { useForemanSettings } from 'foremanReact/Root/Context/ForemanContext';
|
6
|
+
import {
|
7
|
+
withInterval,
|
8
|
+
stopInterval,
|
9
|
+
} from 'foremanReact/redux/middlewares/IntervalMiddleware';
|
5
10
|
|
6
11
|
import {
|
7
12
|
selectItems,
|
8
|
-
|
13
|
+
selectApiStatus,
|
9
14
|
selectAutoRefresh,
|
15
|
+
selectTotalHosts,
|
16
|
+
selectIntervalExists,
|
10
17
|
} from './TargetingHostsSelectors';
|
11
|
-
import {
|
18
|
+
import { getApiUrl } from './TargetingHostsHelpers';
|
12
19
|
import { TARGETING_HOSTS } from './TargetingHostsConsts';
|
20
|
+
import TargetingHostsPage from './TargetingHostsPage';
|
13
21
|
|
14
22
|
const WrappedTargetingHosts = () => {
|
15
23
|
const dispatch = useDispatch();
|
24
|
+
const { perPage, perPageOptions } = useForemanSettings();
|
25
|
+
|
16
26
|
const autoRefresh = useSelector(selectAutoRefresh);
|
17
27
|
const items = useSelector(selectItems);
|
18
|
-
const
|
28
|
+
const apiStatus = useSelector(selectApiStatus);
|
29
|
+
const totalHosts = useSelector(selectTotalHosts);
|
30
|
+
const [searchQuery, setSearchQuery] = useState('');
|
31
|
+
const [pagination, setPagination] = useState({
|
32
|
+
page: 1,
|
33
|
+
perPage,
|
34
|
+
perPageOptions,
|
35
|
+
});
|
36
|
+
const [apiUrl, setApiUrl] = useState(getApiUrl(searchQuery, pagination));
|
37
|
+
const intervalExists = useSelector(selectIntervalExists);
|
19
38
|
|
20
|
-
|
21
|
-
|
39
|
+
const handleSearch = query => {
|
40
|
+
const defaultPagination = { page: 1, perPage: pagination.perPage };
|
41
|
+
stopApiInterval();
|
22
42
|
|
23
|
-
|
43
|
+
setApiUrl(getApiUrl(query, defaultPagination));
|
44
|
+
setSearchQuery(query);
|
45
|
+
setPagination(defaultPagination);
|
46
|
+
};
|
47
|
+
|
48
|
+
const handlePagination = args => {
|
49
|
+
stopApiInterval();
|
50
|
+
setPagination(args);
|
51
|
+
setApiUrl(getApiUrl(searchQuery, args));
|
52
|
+
};
|
53
|
+
|
54
|
+
const stopApiInterval = () => {
|
55
|
+
if (intervalExists) {
|
24
56
|
dispatch(stopInterval(TARGETING_HOSTS));
|
25
|
-
}
|
26
|
-
}
|
57
|
+
}
|
58
|
+
};
|
59
|
+
|
60
|
+
const getData = url =>
|
61
|
+
withInterval(
|
62
|
+
get({
|
63
|
+
key: TARGETING_HOSTS,
|
64
|
+
url,
|
65
|
+
handleError: () => {
|
66
|
+
dispatch(stopInterval(TARGETING_HOSTS));
|
67
|
+
},
|
68
|
+
}),
|
69
|
+
1000
|
70
|
+
);
|
27
71
|
|
28
72
|
useEffect(() => {
|
73
|
+
dispatch(getData(apiUrl));
|
74
|
+
|
29
75
|
if (autoRefresh === 'false') {
|
30
76
|
dispatch(stopInterval(TARGETING_HOSTS));
|
31
77
|
}
|
32
|
-
}, [autoRefresh, dispatch]);
|
33
78
|
|
34
|
-
|
79
|
+
return () => {
|
80
|
+
dispatch(stopInterval(TARGETING_HOSTS));
|
81
|
+
};
|
82
|
+
}, [dispatch, apiUrl, autoRefresh]);
|
83
|
+
|
84
|
+
return (
|
85
|
+
<TargetingHostsPage
|
86
|
+
handleSearch={handleSearch}
|
87
|
+
searchQuery={searchQuery}
|
88
|
+
apiStatus={apiStatus}
|
89
|
+
items={items}
|
90
|
+
totalHosts={totalHosts}
|
91
|
+
pagination={pagination}
|
92
|
+
handlePagination={handlePagination}
|
93
|
+
/>
|
94
|
+
);
|
35
95
|
};
|
36
96
|
|
37
97
|
export default WrappedTargetingHosts;
|