katello 4.8.0.rc2 → 4.8.0
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of katello might be problematic. Click here for more details.
- checksums.yaml +4 -4
- data/lib/katello/plugin.rb +0 -12
- data/lib/katello/version.rb +1 -1
- data/webpack/components/Content/{ContentPage.js → GenericContentPage.js} +7 -4
- data/webpack/components/Content/__tests__/ContentTable.test.js +1 -1
- data/webpack/components/Content/__tests__/GenericContentPage.test.js +35 -0
- data/webpack/components/Search/SearchText.js +70 -0
- data/webpack/components/Table/EmptyStateMessage.js +2 -2
- data/webpack/components/Table/TableWrapper.js +4 -0
- data/webpack/components/extensions/HostDetails/HostDetailsConstants.js +0 -1
- data/webpack/components/extensions/HostDetails/HostDetailsSelectors.js +0 -6
- data/webpack/components/extensions/HostDetails/Tabs/__tests__/moduleStreamsTab.test.js +76 -0
- data/webpack/components/extensions/SearchBar/SearchBarConstants.js +3 -0
- data/webpack/components/extensions/SearchBar/SearchBarHooks.js +50 -0
- data/webpack/components/extensions/SearchBar/SearchBarReducer.js +14 -0
- data/webpack/components/extensions/SearchBar/SearchBarSelectors.js +5 -0
- data/webpack/redux/reducers/index.js +2 -2
- data/webpack/scenes/AlternateContentSources/Create/__tests__/acsCreate.test.js +1 -13
- data/webpack/scenes/AlternateContentSources/MainTable/ACSTable.js +1 -0
- data/webpack/scenes/Content/{ContentPage.js → GenericContentPage.js} +2 -2
- data/webpack/scenes/Content/__tests__/contentTable.test.js +2 -2
- data/webpack/scenes/Content/index.js +2 -2
- data/webpack/scenes/ContentViews/Details/Filters/Rules/ContainerTag/AddEditContainerTagRuleModal.js +14 -17
- data/webpack/scenes/ContentViews/Details/Filters/Rules/Package/AddEditPackageRuleModal.js +24 -28
- data/webpack/scenes/ContentViews/Details/Filters/__tests__/CVContainerImageFilterContent.test.js +11 -18
- data/webpack/scenes/ContentViews/Details/Filters/__tests__/CVRpmFilterContent.test.js +10 -23
- data/webpack/scenes/ContentViews/Details/Filters/__tests__/ContentViewPackageGroupFilter.test.js +0 -2
- data/webpack/scenes/ContentViews/Details/Versions/__tests__/contentViewVersions.test.js +1 -7
- data/webpack/scenes/ContentViews/expansions/__tests__/contentViewComponentsModal.test.js +0 -2
- data/webpack/scenes/ModuleStreams/ModuleStreamsPage.js +2 -2
- data/webpack/scenes/ModuleStreams/__tests__/ModuleStreamPage.test.js +2 -2
- data/webpack/scenes/ModuleStreams/__tests__/__snapshots__/ModuleStreamPage.test.js.snap +1 -1
- data/webpack/scenes/Settings/SettingsConstants.js +2 -3
- data/webpack/scenes/Settings/SettingsReducer.js +2 -16
- data/webpack/scenes/Settings/SettingsSelectors.js +2 -2
- data/webpack/test-utils/react-testing-lib-wrapper.js +0 -6
- metadata +12 -24
- data/webpack/components/Content/__tests__/ContentPage.test.js +0 -32
- data/webpack/components/Content/__tests__/__snapshots__/ContentPage.test.js.snap +0 -89
- data/webpack/components/Search/Search.js +0 -156
- data/webpack/components/Search/__tests__/search.test.js +0 -104
- data/webpack/components/Search/helpers.js +0 -6
- data/webpack/components/Search/index.js +0 -15
- data/webpack/components/TypeAhead/TypeAhead.js +0 -157
- data/webpack/components/TypeAhead/TypeAhead.scss +0 -7
- data/webpack/components/TypeAhead/helpers/commonPropTypes.js +0 -35
- data/webpack/components/TypeAhead/helpers/helpers.js +0 -32
- data/webpack/components/TypeAhead/index.js +0 -3
- data/webpack/components/TypeAhead/pf3Search/TypeAheadInput.js +0 -44
- data/webpack/components/TypeAhead/pf3Search/TypeAheadItems.js +0 -56
- data/webpack/components/TypeAhead/pf3Search/TypeAheadSearch.js +0 -53
- data/webpack/components/TypeAhead/pf4Search/TypeAheadInput.js +0 -66
- data/webpack/components/TypeAhead/pf4Search/TypeAheadInput.scss +0 -12
- data/webpack/components/TypeAhead/pf4Search/TypeAheadItems.js +0 -59
- data/webpack/components/TypeAhead/pf4Search/TypeAheadSearch.js +0 -81
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 2919242e09a707d0f3a395e9aaa41cb10a5df4230c72d9fa9c9a2ea4fec084c8
|
4
|
+
data.tar.gz: 4231fadf860f0c63c5ccbd98e05f96019eae6e91c3e12abf45c22c958ad27c67
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 3c3c89ea507b6f247fb1b40b17e615c903e24475b63f9b19d19ebfe1c7d284629b089c87358b3f9a0e35f09b78109823509826c70e21a21dfb8de20ade93a574
|
7
|
+
data.tar.gz: d71b28cc37b495a5a836031b7598819070e58c881c5e77bfe292816c2639508dbf075ef5d1234f31b96480a6ea131a8fdbdec0ea4609c2fbccab1a78cc96f5cf
|
data/lib/katello/plugin.rb
CHANGED
@@ -651,18 +651,6 @@ Foreman::Plugin.register :katello do
|
|
651
651
|
full_name: N_('Applicability Batch Size'),
|
652
652
|
description: N_("Number of host applicability calculations to process per task.")
|
653
653
|
|
654
|
-
setting 'autosearch_while_typing',
|
655
|
-
type: :boolean,
|
656
|
-
default: true,
|
657
|
-
full_name: N_('Autosearch'),
|
658
|
-
description: N_('For pages that support it, automatically perform search while typing in search input.')
|
659
|
-
|
660
|
-
setting 'autosearch_delay',
|
661
|
-
type: :integer,
|
662
|
-
default: 500,
|
663
|
-
full_name: N_('Autosearch delay'),
|
664
|
-
description: N_('If Autosearch is enabled, delay in milliseconds before executing searches while typing.')
|
665
|
-
|
666
654
|
setting 'bulk_load_size',
|
667
655
|
type: :integer,
|
668
656
|
default: 2000,
|
data/lib/katello/version.rb
CHANGED
@@ -4,8 +4,9 @@ import { Grid, Col, Row, Form, FormGroup } from 'react-bootstrap';
|
|
4
4
|
import SearchBar from 'foremanReact/components/SearchBar';
|
5
5
|
import { getControllerSearchProps } from 'foremanReact/constants';
|
6
6
|
import ContentTable from './ContentTable';
|
7
|
+
import { useClearSearch } from '../extensions/SearchBar/SearchBarHooks';
|
7
8
|
|
8
|
-
const
|
9
|
+
const GenericContentPage = ({
|
9
10
|
header, onSearch, bookmarkController,
|
10
11
|
autocompleteEndpoint, autocompleteQueryParams,
|
11
12
|
updateSearchQuery, initialInputValue,
|
@@ -15,6 +16,7 @@ const ContentPage = ({
|
|
15
16
|
...getControllerSearchProps(autocompleteEndpoint, `searchBar-content-page-${header}`, true, autocompleteQueryParams),
|
16
17
|
controller: bookmarkController,
|
17
18
|
};
|
19
|
+
const searchBarKey = useClearSearch({ updateSearchQuery });
|
18
20
|
return (
|
19
21
|
<Grid bsClass="container-fluid">
|
20
22
|
<Row>
|
@@ -27,6 +29,7 @@ const ContentPage = ({
|
|
27
29
|
<Form className="toolbar-pf-actions">
|
28
30
|
<FormGroup className="toolbar-pf toolbar-pf-filter">
|
29
31
|
<SearchBar
|
32
|
+
key={searchBarKey}
|
30
33
|
data={searchDataProp}
|
31
34
|
onSearch={onSearch}
|
32
35
|
onSearchChange={updateSearchQuery}
|
@@ -49,7 +52,7 @@ const ContentPage = ({
|
|
49
52
|
);
|
50
53
|
};
|
51
54
|
|
52
|
-
|
55
|
+
GenericContentPage.propTypes = {
|
53
56
|
header: PropTypes.string.isRequired,
|
54
57
|
content: PropTypes.shape({}).isRequired,
|
55
58
|
tableSchema: PropTypes.arrayOf(PropTypes.shape({})).isRequired,
|
@@ -62,10 +65,10 @@ ContentPage.propTypes = {
|
|
62
65
|
bookmarkController: PropTypes.string,
|
63
66
|
};
|
64
67
|
|
65
|
-
|
68
|
+
GenericContentPage.defaultProps = {
|
66
69
|
autocompleteEndpoint: undefined,
|
67
70
|
autocompleteQueryParams: undefined,
|
68
71
|
bookmarkController: undefined,
|
69
72
|
};
|
70
73
|
|
71
|
-
export default
|
74
|
+
export default GenericContentPage;
|
@@ -1,9 +1,9 @@
|
|
1
1
|
import React from 'react';
|
2
2
|
import { shallow } from 'enzyme';
|
3
3
|
import toJson from 'enzyme-to-json';
|
4
|
-
import ContentTable from '../ContentTable';
|
5
4
|
import { LoadingState } from '../../../components/LoadingState';
|
6
5
|
import { Table } from '../../../components/pf3Table';
|
6
|
+
import ContentTable from '../ContentTable';
|
7
7
|
|
8
8
|
describe('Content Table', () => {
|
9
9
|
it('should render and contain appropriate components', async () => {
|
@@ -0,0 +1,35 @@
|
|
1
|
+
import React from 'react';
|
2
|
+
import { act } from 'react-test-renderer';
|
3
|
+
import { renderWithRedux, patientlyWaitFor } from 'react-testing-lib-wrapper';
|
4
|
+
import { CONTENT_KEY } from '../../../scenes/Content/ContentConstants';
|
5
|
+
import GenericContentPage from '../GenericContentPage';
|
6
|
+
|
7
|
+
const renderOptions = () => ({
|
8
|
+
apiNamespace: CONTENT_KEY,
|
9
|
+
});
|
10
|
+
|
11
|
+
test('Can render the basic component with no data', async (done) => {
|
12
|
+
const contentHeader = 'Content Header';
|
13
|
+
const content = { results: [] };
|
14
|
+
const onSearch = jest.fn();
|
15
|
+
const updateSearchQuery = jest.fn();
|
16
|
+
const searchQuery = '';
|
17
|
+
const onPaginationChange = jest.fn();
|
18
|
+
const TableSchema = [];
|
19
|
+
const bookmarkController = 'module_streams';
|
20
|
+
|
21
|
+
const { getByText } = renderWithRedux(<GenericContentPage
|
22
|
+
header={contentHeader}
|
23
|
+
content={content}
|
24
|
+
tableSchema={TableSchema}
|
25
|
+
onSearch={onSearch}
|
26
|
+
updateSearchQuery={updateSearchQuery}
|
27
|
+
initialInputValue={searchQuery}
|
28
|
+
onPaginationChange={onPaginationChange}
|
29
|
+
bookmarkController={bookmarkController}
|
30
|
+
/>, renderOptions());
|
31
|
+
|
32
|
+
await patientlyWaitFor(() =>
|
33
|
+
expect(getByText(contentHeader)).toBeInTheDocument());
|
34
|
+
act(done);
|
35
|
+
});
|
@@ -0,0 +1,70 @@
|
|
1
|
+
import React, { useState } from 'react';
|
2
|
+
import PropTypes from 'prop-types';
|
3
|
+
import { SearchAutocomplete } from 'foremanReact/components/SearchBar/SearchAutocomplete';
|
4
|
+
import { useAPI } from 'foremanReact/common/hooks/API/APIHooks';
|
5
|
+
import { STATUS } from 'foremanReact/constants';
|
6
|
+
import { noop } from 'foremanReact/common/helpers';
|
7
|
+
|
8
|
+
const SearchText = ({
|
9
|
+
data: {
|
10
|
+
autocomplete: { url, apiParams } = { url: '' },
|
11
|
+
disabled,
|
12
|
+
},
|
13
|
+
initialQuery,
|
14
|
+
onSearchChange,
|
15
|
+
name,
|
16
|
+
}) => {
|
17
|
+
const [search, setSearch] = useState(initialQuery || '');
|
18
|
+
const getAPIparams = input => ({ ...apiParams(input) });
|
19
|
+
const { response, status, setAPIOptions } = useAPI('get', url, {
|
20
|
+
params: getAPIparams(search),
|
21
|
+
});
|
22
|
+
const onChange = (newValue) => {
|
23
|
+
onSearchChange(newValue);
|
24
|
+
setSearch(newValue);
|
25
|
+
setAPIOptions({ params: { ...getAPIparams(newValue) } });
|
26
|
+
};
|
27
|
+
const error =
|
28
|
+
status === STATUS.ERROR || response?.[0]?.error
|
29
|
+
? response?.[0]?.error || response.message
|
30
|
+
: null;
|
31
|
+
|
32
|
+
let results = [];
|
33
|
+
if (Array.isArray(response) && !error) {
|
34
|
+
results = response.map(item => ({ label: item, category: '' }));
|
35
|
+
}
|
36
|
+
|
37
|
+
return (
|
38
|
+
<div className="foreman-search-text">
|
39
|
+
<SearchAutocomplete
|
40
|
+
results={results}
|
41
|
+
onSearchChange={onChange}
|
42
|
+
value={search}
|
43
|
+
disabled={disabled}
|
44
|
+
error={error}
|
45
|
+
name={name}
|
46
|
+
/>
|
47
|
+
</div>
|
48
|
+
);
|
49
|
+
};
|
50
|
+
|
51
|
+
SearchText.propTypes = {
|
52
|
+
data: PropTypes.shape({
|
53
|
+
autocomplete: PropTypes.shape({
|
54
|
+
url: PropTypes.string.isRequired,
|
55
|
+
apiParams: PropTypes.func,
|
56
|
+
}).isRequired,
|
57
|
+
disabled: PropTypes.bool,
|
58
|
+
}).isRequired,
|
59
|
+
initialQuery: PropTypes.string,
|
60
|
+
onSearchChange: PropTypes.func,
|
61
|
+
name: PropTypes.string,
|
62
|
+
};
|
63
|
+
|
64
|
+
SearchText.defaultProps = {
|
65
|
+
initialQuery: '',
|
66
|
+
onSearchChange: noop,
|
67
|
+
name: null,
|
68
|
+
};
|
69
|
+
|
70
|
+
export default SearchText;
|
@@ -14,7 +14,7 @@ import { translate as __ } from 'foremanReact/common/I18n';
|
|
14
14
|
import { CubeIcon, ExclamationCircleIcon, SearchIcon, CheckCircleIcon, PlusCircleIcon } from '@patternfly/react-icons';
|
15
15
|
import { global_danger_color_200 as dangerColor, global_success_color_100 as successColor } from '@patternfly/react-tokens';
|
16
16
|
import { useDispatch, useSelector } from 'react-redux';
|
17
|
-
import {
|
17
|
+
import { selectSearchBarClearSearch } from '../extensions/SearchBar/SearchBarSelectors';
|
18
18
|
|
19
19
|
const KatelloEmptyStateIcon = ({
|
20
20
|
error, search, customIcon, happyIcon,
|
@@ -51,7 +51,7 @@ const EmptyStateMessage = ({
|
|
51
51
|
const defaultSecondaryActionText = searchIsActive ? __('Clear search') : __('Clear filters');
|
52
52
|
const secondaryActionText = secondaryActionTextOverride || defaultSecondaryActionText;
|
53
53
|
const dispatch = useDispatch();
|
54
|
-
const clearSearch = useSelector(
|
54
|
+
const clearSearch = useSelector(selectSearchBarClearSearch);
|
55
55
|
const showSecondaryActionAnchor = showSecondaryAction && secondaryActionLink;
|
56
56
|
const handleClick = () => {
|
57
57
|
if (searchIsActive) {
|
@@ -14,6 +14,7 @@ import MainTable from './MainTable';
|
|
14
14
|
import { getPageStats } from './helpers';
|
15
15
|
import SelectAllCheckbox from '../SelectAllCheckbox';
|
16
16
|
import { orgId } from '../../services/api';
|
17
|
+
import { useClearSearch } from '../extensions/SearchBar/SearchBarHooks';
|
17
18
|
|
18
19
|
/* Patternfly 4 table wrapper */
|
19
20
|
const TableWrapper = ({
|
@@ -132,6 +133,8 @@ const TableWrapper = ({
|
|
132
133
|
spawnFetch();
|
133
134
|
}, [searchQuery, spawnFetch, additionalListeners]);
|
134
135
|
|
136
|
+
const searchBarKey = useClearSearch({ updateSearchQuery });
|
137
|
+
|
135
138
|
// If the new page wouldn't exist because of a perPage change,
|
136
139
|
// we should set the current page to the last page.
|
137
140
|
const validatePagination = (data) => {
|
@@ -194,6 +197,7 @@ const TableWrapper = ({
|
|
194
197
|
data={searchDataProp}
|
195
198
|
initialQuery={searchQuery}
|
196
199
|
onSearch={search => updateSearchQuery(search)}
|
200
|
+
key={searchBarKey}
|
197
201
|
/>
|
198
202
|
</FlexItem>
|
199
203
|
}
|
@@ -14,9 +14,3 @@ export const selectHostDetailsStatus = state =>
|
|
14
14
|
|
15
15
|
export const selectHostDetailsError = state =>
|
16
16
|
selectAPIError(state, HOST_DETAILS_KEY);
|
17
|
-
|
18
|
-
export const selectHostDetailsState = state =>
|
19
|
-
state.katello.hostDetails;
|
20
|
-
|
21
|
-
export const selectHostDetailsClearSearch = state =>
|
22
|
-
selectHostDetailsState(state).clearSearch;
|
@@ -93,6 +93,82 @@ test('Can handle no Module streams being present', async (done) => {
|
|
93
93
|
act(done);
|
94
94
|
});
|
95
95
|
|
96
|
+
test('When there are no search results, can display an empty state with a clear search link that works', async (done) => {
|
97
|
+
// Setup autocomplete with mockForemanAutoComplete since we aren't adding /katello
|
98
|
+
const autocompleteScope = mockForemanAutocomplete(nockInstance, autocompleteUrl);
|
99
|
+
const noResults = {
|
100
|
+
total: 0,
|
101
|
+
subtotal: 0,
|
102
|
+
page: 1,
|
103
|
+
search: 'bad search',
|
104
|
+
per_page: 20,
|
105
|
+
results: [],
|
106
|
+
};
|
107
|
+
|
108
|
+
const initialScope = nockInstance
|
109
|
+
.get(hostModuleStreams)
|
110
|
+
.query(true)
|
111
|
+
.times(1)
|
112
|
+
.reply(200, mockModuleStreams);
|
113
|
+
|
114
|
+
const badSearchScope = nockInstance
|
115
|
+
.get(hostModuleStreams)
|
116
|
+
.query({
|
117
|
+
sort_by: 'name',
|
118
|
+
sort_order: 'asc',
|
119
|
+
per_page: '20',
|
120
|
+
page: '1',
|
121
|
+
search: 'bad search',
|
122
|
+
})
|
123
|
+
.reply(200, noResults);
|
124
|
+
|
125
|
+
const badAutoCompleteScope =
|
126
|
+
mockForemanAutocomplete(
|
127
|
+
nockInstance,
|
128
|
+
autocompleteUrl,
|
129
|
+
true,
|
130
|
+
[],
|
131
|
+
2, // times
|
132
|
+
);
|
133
|
+
|
134
|
+
const scopeWithoutSearch = nockInstance
|
135
|
+
.get(hostModuleStreams)
|
136
|
+
.query(true)
|
137
|
+
.reply(200, mockModuleStreams);
|
138
|
+
|
139
|
+
const { queryByText, getByRole } = renderWithRedux(<ModuleStreamsTab />, renderOptions());
|
140
|
+
|
141
|
+
|
142
|
+
await patientlyWaitFor(() => expect(queryByText(firstModuleStreams.name)).toBeInTheDocument());
|
143
|
+
|
144
|
+
const searchInput = getByRole('textbox', { name: 'Search input' });
|
145
|
+
// Foreman SearchAutocomplete doesn't run onSearchChange unless the element is focused!
|
146
|
+
searchInput.focus();
|
147
|
+
|
148
|
+
fireEvent.change(searchInput, { target: { value: 'bad search' } });
|
149
|
+
expect(searchInput.value).toBe('bad search');
|
150
|
+
const searchButton = getByRole('button', { name: 'Search' });
|
151
|
+
expect(searchButton).not.toHaveAttribute('aria-disabled', true);
|
152
|
+
fireEvent.click(searchButton);
|
153
|
+
|
154
|
+
await patientlyWaitFor(() => expect(queryByText('Your search returned no matching Module streams.')).toBeInTheDocument());
|
155
|
+
// Now click the clear search link and assert that the search is cleared and the results are back
|
156
|
+
const clearSearchLink = getByRole('button', { name: 'Clear search' });
|
157
|
+
fireEvent.click(clearSearchLink);
|
158
|
+
|
159
|
+
await patientlyWaitFor(() => {
|
160
|
+
expect(queryByText(firstModuleStreams.name)).toBeInTheDocument();
|
161
|
+
expect(getByRole('textbox', { name: 'Search input' }).value).toBe('');
|
162
|
+
expect(queryByText('Clear search')).not.toBeInTheDocument();
|
163
|
+
});
|
164
|
+
|
165
|
+
assertNockRequest(initialScope);
|
166
|
+
assertNockRequest(badAutoCompleteScope);
|
167
|
+
assertNockRequest(badSearchScope);
|
168
|
+
assertNockRequest(scopeWithoutSearch);
|
169
|
+
assertNockRequest(autocompleteScope, done);
|
170
|
+
});
|
171
|
+
|
96
172
|
test('Can filter results based on status', async (done) => {
|
97
173
|
const autocompleteScope = mockForemanAutocomplete(nockInstance, autocompleteUrl);
|
98
174
|
const scope = nockInstance
|
@@ -0,0 +1,50 @@
|
|
1
|
+
import { useEffect, useCallback, useRef } from 'react';
|
2
|
+
import { useDispatch, useSelector } from 'react-redux';
|
3
|
+
import { selectSearchBarClearSearch } from './SearchBarSelectors';
|
4
|
+
|
5
|
+
export const useClearSearch = ({
|
6
|
+
updateSearchQuery,
|
7
|
+
}) => {
|
8
|
+
const dispatch = useDispatch();
|
9
|
+
// We keep the clearSearch function in Redux to avoid prop drilling and make EmptyStateMessage
|
10
|
+
// more reusable both with and without TableWrapper.
|
11
|
+
const existingClearSearch = useSelector(selectSearchBarClearSearch);
|
12
|
+
// In Katello we don't have access to Foreman <SearchBar /> component's internal state,
|
13
|
+
// so we don't have an easy way to clear the search input. We can use a counter to
|
14
|
+
// pass as a key prop to the <SearchBar /> component, which will force it to reset
|
15
|
+
// its internal state when clearSearch is called.
|
16
|
+
const counter = useRef(0);
|
17
|
+
|
18
|
+
const clearSearch = useCallback(() => {
|
19
|
+
counter.current += 1; // reset the text input
|
20
|
+
if (typeof updateSearchQuery !== 'function') {
|
21
|
+
// eslint-disable-next-line no-console
|
22
|
+
console.error('You must pass the updateSearchQuery function to useClearSearch');
|
23
|
+
return;
|
24
|
+
}
|
25
|
+
updateSearchQuery(''); // make a new API call with blank search query
|
26
|
+
}, [updateSearchQuery]);
|
27
|
+
|
28
|
+
useEffect(() => {
|
29
|
+
if (typeof existingClearSearch !== 'function') {
|
30
|
+
dispatch({
|
31
|
+
type: 'SET_CLEAR_SEARCH',
|
32
|
+
payload: clearSearch,
|
33
|
+
});
|
34
|
+
}
|
35
|
+
}, [dispatch, existingClearSearch, clearSearch]);
|
36
|
+
|
37
|
+
// eslint-disable-next-line arrow-body-style
|
38
|
+
useEffect(() => {
|
39
|
+
return function cleanupClearSearch() {
|
40
|
+
dispatch({
|
41
|
+
type: 'SET_CLEAR_SEARCH',
|
42
|
+
payload: {},
|
43
|
+
});
|
44
|
+
};
|
45
|
+
}, [dispatch]);
|
46
|
+
|
47
|
+
return `search-bar-${counter.current}`;
|
48
|
+
};
|
49
|
+
|
50
|
+
export default useClearSearch;
|
@@ -0,0 +1,14 @@
|
|
1
|
+
import Immutable from 'seamless-immutable';
|
2
|
+
|
3
|
+
import { SET_CLEAR_SEARCH } from './SearchBarConstants';
|
4
|
+
|
5
|
+
const initialState = Immutable({ clearSearch: undefined });
|
6
|
+
|
7
|
+
export default (state = initialState, action) => {
|
8
|
+
switch (action.type) {
|
9
|
+
case SET_CLEAR_SEARCH:
|
10
|
+
return state.set('clearSearch', action.payload);
|
11
|
+
default:
|
12
|
+
return state;
|
13
|
+
}
|
14
|
+
};
|
@@ -4,7 +4,6 @@ import redHatRepositories from './RedHatRepositories';
|
|
4
4
|
import { subscriptions } from '../../scenes/Subscriptions';
|
5
5
|
import { upstreamSubscriptions } from '../../scenes/Subscriptions/UpstreamSubscriptions';
|
6
6
|
import { manifestHistory } from '../../scenes/Subscriptions/Manifest';
|
7
|
-
import settings from '../../scenes/Settings';
|
8
7
|
import { subscriptionDetails } from '../../scenes/Subscriptions/Details';
|
9
8
|
import { setOrganization } from '../../components/SelectOrg/SetOrganization';
|
10
9
|
import { moduleStreams } from '../../scenes/ModuleStreams';
|
@@ -13,6 +12,7 @@ import { moduleStreamDetails } from '../../scenes/ModuleStreams/Details';
|
|
13
12
|
import { reducers as systemStatuses } from '../../components/extensions/about';
|
14
13
|
import { contentViewDetails } from '../../scenes/ContentViews/Details';
|
15
14
|
import hostDetails from '../../components/extensions/HostDetails/HostDetailsReducer';
|
15
|
+
import searchBar from '../../components/extensions/SearchBar/SearchBarReducer';
|
16
16
|
|
17
17
|
export default combineReducers({
|
18
18
|
organization,
|
@@ -20,13 +20,13 @@ export default combineReducers({
|
|
20
20
|
subscriptions,
|
21
21
|
upstreamSubscriptions,
|
22
22
|
manifestHistory,
|
23
|
-
settings,
|
24
23
|
subscriptionDetails,
|
25
24
|
setOrganization,
|
26
25
|
moduleStreams,
|
27
26
|
moduleStreamDetails,
|
28
27
|
contentViewDetails,
|
29
28
|
hostDetails,
|
29
|
+
searchBar,
|
30
30
|
...organizationProductsReducers,
|
31
31
|
...systemStatuses,
|
32
32
|
});
|
@@ -3,7 +3,7 @@ import * as reactRedux from 'react-redux';
|
|
3
3
|
import { Route } from 'react-router-dom';
|
4
4
|
import { act, fireEvent, patientlyWaitFor, renderWithRedux } from 'react-testing-lib-wrapper';
|
5
5
|
import api, { foremanApi } from '../../../../services/api';
|
6
|
-
import { assertNockRequest, mockAutocomplete,
|
6
|
+
import { assertNockRequest, mockAutocomplete, nockInstance } from '../../../../test-utils/nockWrapper';
|
7
7
|
import ACSTable from '../../MainTable/ACSTable';
|
8
8
|
import contentCredentialResult from './contentCredentials.fixtures';
|
9
9
|
import smartProxyResult from './smartProxy.fixtures';
|
@@ -70,18 +70,6 @@ const renderOptions = {
|
|
70
70
|
},
|
71
71
|
};
|
72
72
|
|
73
|
-
let searchDelayScope;
|
74
|
-
let autoSearchScope;
|
75
|
-
beforeEach(() => {
|
76
|
-
searchDelayScope = mockSetting(nockInstance, 'autosearch_delay', 0);
|
77
|
-
autoSearchScope = mockSetting(nockInstance, 'autosearch_while_typing');
|
78
|
-
});
|
79
|
-
|
80
|
-
afterEach(() => {
|
81
|
-
assertNockRequest(searchDelayScope);
|
82
|
-
assertNockRequest(autoSearchScope);
|
83
|
-
});
|
84
|
-
|
85
73
|
test('Can show add ACS button if can_create is true', async (done) => {
|
86
74
|
const autocompleteScope = mockAutocomplete(nockInstance, autocompleteUrl);
|
87
75
|
const scope = nockInstance
|
@@ -12,7 +12,7 @@ import { getContentTypes } from './ContentActions';
|
|
12
12
|
import Loading from '../../components/Loading';
|
13
13
|
import EmptyStateMessage from '../../components/Table/EmptyStateMessage';
|
14
14
|
|
15
|
-
const
|
15
|
+
const GenericContentPage = () => {
|
16
16
|
const dispatch = useDispatch();
|
17
17
|
const contentTypesResponse = useSelector(selectContentTypes);
|
18
18
|
const contentTypesStatus = useSelector(selectContentTypesStatus);
|
@@ -86,4 +86,4 @@ const ContentPage = () => {
|
|
86
86
|
);
|
87
87
|
};
|
88
88
|
|
89
|
-
export default
|
89
|
+
export default GenericContentPage;
|
@@ -2,7 +2,7 @@ import React from 'react';
|
|
2
2
|
import { renderWithRedux, patientlyWaitFor } from 'react-testing-lib-wrapper';
|
3
3
|
import { nockInstance, assertNockRequest, mockAutocomplete } from '../../../test-utils/nockWrapper';
|
4
4
|
import api from '../../../services/api';
|
5
|
-
import
|
5
|
+
import GenericContentPage from '../GenericContentPage';
|
6
6
|
import ansibleCollectionsResponse from './ansibleCollections.fixtures';
|
7
7
|
import contentTypesResponse from './contentTypes.fixtures.json';
|
8
8
|
import pythonPackagesResponse from './pythonPackages.fixtures.json';
|
@@ -29,7 +29,7 @@ test('Can call API for Python Packages and show table on page load', async (done
|
|
29
29
|
.reply(200, contentTypesResponse);
|
30
30
|
|
31
31
|
const { queryByText, getAllByText } =
|
32
|
-
renderWithRedux(<
|
32
|
+
renderWithRedux(<GenericContentPage />);
|
33
33
|
|
34
34
|
expect(queryByText(firstPackage.name)).toBeNull();
|
35
35
|
await patientlyWaitFor(() => {
|
data/webpack/scenes/ContentViews/Details/Filters/Rules/ContainerTag/AddEditContainerTagRuleModal.js
CHANGED
@@ -5,7 +5,7 @@ import { translate as __ } from 'foremanReact/common/I18n';
|
|
5
5
|
import { Modal, ModalVariant, Form, FormGroup, ActionGroup, Button } from '@patternfly/react-core';
|
6
6
|
import { addCVFilterRule, editCVFilterRule, getCVFilterRules } from '../../../ContentViewDetailActions';
|
7
7
|
import { orgId } from '../../../../../../services/api';
|
8
|
-
import
|
8
|
+
import SearchText from '../../../../../../components/Search/SearchText';
|
9
9
|
|
10
10
|
const AddEditContainerTagRuleModal = ({
|
11
11
|
onClose, filterId, selectedFilterRuleData, repositoryIds,
|
@@ -16,7 +16,7 @@ const AddEditContainerTagRuleModal = ({
|
|
16
16
|
const [saving, setSaving] = useState(false);
|
17
17
|
const isEditing = name && id;
|
18
18
|
|
19
|
-
const autoCompleteEndpoint = '/docker_tags/auto_complete_name';
|
19
|
+
const autoCompleteEndpoint = '/katello/api/v2/docker_tags/auto_complete_name';
|
20
20
|
|
21
21
|
const onSubmit = () => {
|
22
22
|
setSaving(true);
|
@@ -36,13 +36,10 @@ const AddEditContainerTagRuleModal = ({
|
|
36
36
|
onClose();
|
37
37
|
};
|
38
38
|
|
39
|
-
const
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
term,
|
44
|
-
repoids: repositoryIds,
|
45
|
-
},
|
39
|
+
const searchDataProp = term => ({
|
40
|
+
organization_id: orgId(),
|
41
|
+
term,
|
42
|
+
repoids: repositoryIds,
|
46
43
|
});
|
47
44
|
|
48
45
|
return (
|
@@ -59,14 +56,14 @@ const AddEditContainerTagRuleModal = ({
|
|
59
56
|
}}
|
60
57
|
>
|
61
58
|
<FormGroup label={__('Tag name')} isRequired fieldId="tag_name">
|
62
|
-
<
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
59
|
+
<SearchText
|
60
|
+
data={{
|
61
|
+
autocomplete: {
|
62
|
+
url: autoCompleteEndpoint,
|
63
|
+
apiParams: tag => searchDataProp(tag),
|
64
|
+
},
|
65
|
+
}}
|
66
|
+
onSearchChange={setTagName}
|
70
67
|
/>
|
71
68
|
</FormGroup>
|
72
69
|
<ActionGroup>
|