katello 4.8.0.rc2 → 4.8.1
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/app/controllers/katello/api/v2/simple_content_access_controller.rb +3 -1
- data/app/lib/actions/katello/content_view/publish.rb +2 -9
- data/app/lib/actions/katello/organization/simple_content_access/enable.rb +10 -0
- data/app/lib/actions/katello/organization/simple_content_access/prepare_content_overrides.rb +36 -0
- data/app/lib/actions/katello/organization/simple_content_access/toggle.rb +12 -2
- data/app/lib/katello/util/content_overrides_migrator.rb +98 -0
- data/app/models/katello/content_view.rb +10 -6
- data/app/models/katello/host/content_facet.rb +10 -3
- data/db/migrate/20220110223754_update_disconnected_settings.rb +8 -4
- data/db/migrate/20230119003859_ensure_repo_username_password_nil_not_blank.rb +1 -1
- data/lib/katello/plugin.rb +0 -12
- data/lib/katello/version.rb +1 -1
- data/locale/bn/LC_MESSAGES/katello.mo +0 -0
- data/locale/cs/LC_MESSAGES/katello.mo +0 -0
- data/locale/de/LC_MESSAGES/katello.mo +0 -0
- data/locale/en/LC_MESSAGES/katello.mo +0 -0
- data/locale/es/LC_MESSAGES/katello.mo +0 -0
- data/locale/fr/LC_MESSAGES/katello.mo +0 -0
- data/locale/gu/LC_MESSAGES/katello.mo +0 -0
- data/locale/hi/LC_MESSAGES/katello.mo +0 -0
- data/locale/it/LC_MESSAGES/katello.mo +0 -0
- data/locale/ja/LC_MESSAGES/katello.mo +0 -0
- data/locale/ka/LC_MESSAGES/katello.mo +0 -0
- data/locale/kn/LC_MESSAGES/katello.mo +0 -0
- data/locale/ko/LC_MESSAGES/katello.mo +0 -0
- data/locale/mr/LC_MESSAGES/katello.mo +0 -0
- data/locale/or/LC_MESSAGES/katello.mo +0 -0
- data/locale/pa/LC_MESSAGES/katello.mo +0 -0
- data/locale/pt/LC_MESSAGES/katello.mo +0 -0
- data/locale/pt_BR/LC_MESSAGES/katello.mo +0 -0
- data/locale/ru/LC_MESSAGES/katello.mo +0 -0
- data/locale/ta/LC_MESSAGES/katello.mo +0 -0
- data/locale/te/LC_MESSAGES/katello.mo +0 -0
- data/locale/zh_CN/LC_MESSAGES/katello.mo +0 -0
- data/locale/zh_TW/LC_MESSAGES/katello.mo +0 -0
- 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/ModuleStreamsTab/ModuleStreamsTab.js +2 -2
- 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 +45 -26
- 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
|
@@ -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>
|
|
@@ -13,7 +13,7 @@ import {
|
|
|
13
13
|
selectCreateFilterRuleStatus,
|
|
14
14
|
} from '../../../ContentViewDetailSelectors';
|
|
15
15
|
import { orgId } from '../../../../../../services/api';
|
|
16
|
-
import
|
|
16
|
+
import SearchText from '../../../../../../components/Search/SearchText';
|
|
17
17
|
|
|
18
18
|
const AddEditPackageRuleModal = ({
|
|
19
19
|
filterId, onClose, selectedFilterRuleData, repositoryIds,
|
|
@@ -27,8 +27,8 @@ const AddEditPackageRuleModal = ({
|
|
|
27
27
|
max_version: editingMaxVersion,
|
|
28
28
|
} = selectedFilterRuleData || {};
|
|
29
29
|
|
|
30
|
-
const architectureAutoCompleteEndpoint = '/packages/auto_complete_arch';
|
|
31
|
-
const nameAutoCompleteEndpoint = '/packages/auto_complete_name';
|
|
30
|
+
const architectureAutoCompleteEndpoint = '/katello/api/v2/packages/auto_complete_arch';
|
|
31
|
+
const nameAutoCompleteEndpoint = '/katello/api/v2/packages/auto_complete_name';
|
|
32
32
|
|
|
33
33
|
const isEditing = !!selectedFilterRuleData;
|
|
34
34
|
|
|
@@ -118,14 +118,11 @@ const AddEditPackageRuleModal = ({
|
|
|
118
118
|
}
|
|
119
119
|
}, [status, setSaving]);
|
|
120
120
|
|
|
121
|
-
const
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
repoids: repositoryIds,
|
|
127
|
-
non_modular: true,
|
|
128
|
-
},
|
|
121
|
+
const searchDataProp = term => ({
|
|
122
|
+
organization_id: orgId(),
|
|
123
|
+
term,
|
|
124
|
+
repoids: repositoryIds,
|
|
125
|
+
non_modular: true,
|
|
129
126
|
});
|
|
130
127
|
|
|
131
128
|
return (
|
|
@@ -142,26 +139,25 @@ const AddEditPackageRuleModal = ({
|
|
|
142
139
|
}}
|
|
143
140
|
>
|
|
144
141
|
<FormGroup label={__('RPM name')} isRequired fieldId="name">
|
|
145
|
-
<
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
142
|
+
<SearchText
|
|
143
|
+
data={{
|
|
144
|
+
autocomplete: {
|
|
145
|
+
url: nameAutoCompleteEndpoint,
|
|
146
|
+
apiParams: input => searchDataProp(input),
|
|
147
|
+
},
|
|
148
|
+
}}
|
|
149
|
+
onSearchChange={setName}
|
|
153
150
|
/>
|
|
154
151
|
</FormGroup>
|
|
155
152
|
<FormGroup label={__('Architecture')} fieldId="architecture">
|
|
156
|
-
<
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
setTextInputValue={setArchitecture}
|
|
153
|
+
<SearchText
|
|
154
|
+
data={{
|
|
155
|
+
autocomplete: {
|
|
156
|
+
url: architectureAutoCompleteEndpoint,
|
|
157
|
+
apiParams: arch => searchDataProp(arch),
|
|
158
|
+
},
|
|
159
|
+
}}
|
|
160
|
+
onSearchChange={setArchitecture}
|
|
165
161
|
/>
|
|
166
162
|
</FormGroup>
|
|
167
163
|
<FormGroup label={__('Version')} fieldId="version_comparator">
|
data/webpack/scenes/ContentViews/Details/Filters/__tests__/CVContainerImageFilterContent.test.js
CHANGED
|
@@ -7,7 +7,6 @@ import {
|
|
|
7
7
|
nockInstance,
|
|
8
8
|
assertNockRequest,
|
|
9
9
|
mockAutocomplete,
|
|
10
|
-
mockSetting,
|
|
11
10
|
} from '../../../../../test-utils/nockWrapper';
|
|
12
11
|
import api from '../../../../../services/api';
|
|
13
12
|
import CVContainerImageFilterContent from '../CVContainerImageFilterContent';
|
|
@@ -140,8 +139,6 @@ test('Can add filter rules', async (done) => {
|
|
|
140
139
|
2,
|
|
141
140
|
);
|
|
142
141
|
const autocompleteNameScope = mockAutocomplete(nockInstance, autocompleteNameUrl, true, [], 2);
|
|
143
|
-
const searchDelayScope = mockSetting(nockInstance, 'autosearch_delay', 0);
|
|
144
|
-
const autoSearchScope = mockSetting(nockInstance, 'autosearch_while_typing');
|
|
145
142
|
|
|
146
143
|
const cvFiltersScope = nockInstance
|
|
147
144
|
.get(cvFilterRulesPath)
|
|
@@ -158,7 +155,7 @@ test('Can add filter rules', async (done) => {
|
|
|
158
155
|
.query(true)
|
|
159
156
|
.reply(200, { ...cvFilterFixtures, results: [...cvFilterFixtures.results, addedRule] });
|
|
160
157
|
|
|
161
|
-
const { queryByText, getByLabelText } =
|
|
158
|
+
const { queryByText, getByLabelText, getAllByLabelText } =
|
|
162
159
|
renderWithRedux(
|
|
163
160
|
withCVRoute(<CVContainerImageFilterContent filterId={195} details={details} />),
|
|
164
161
|
renderOptions,
|
|
@@ -177,7 +174,9 @@ test('Can add filter rules', async (done) => {
|
|
|
177
174
|
expect(getByLabelText('add_edit_filter_rule')).toHaveAttribute('aria-disabled', 'true');
|
|
178
175
|
});
|
|
179
176
|
|
|
180
|
-
|
|
177
|
+
const searchInput = getAllByLabelText('Search input')[1];
|
|
178
|
+
searchInput.focus();
|
|
179
|
+
fireEvent.change(searchInput, { target: { value: 'new-rule' } });
|
|
181
180
|
fireEvent.submit(getByLabelText('add_edit_filter_rule'));
|
|
182
181
|
|
|
183
182
|
await patientlyWaitFor(() => {
|
|
@@ -185,8 +184,6 @@ test('Can add filter rules', async (done) => {
|
|
|
185
184
|
});
|
|
186
185
|
|
|
187
186
|
assertNockRequest(autocompleteScope);
|
|
188
|
-
assertNockRequest(searchDelayScope);
|
|
189
|
-
assertNockRequest(autoSearchScope);
|
|
190
187
|
assertNockRequest(cvFiltersScope);
|
|
191
188
|
assertNockRequest(cvFilterAddScope);
|
|
192
189
|
assertNockRequest(autocompleteNameScope);
|
|
@@ -205,8 +202,6 @@ test('Can edit filter rules', async (done) => {
|
|
|
205
202
|
2,
|
|
206
203
|
);
|
|
207
204
|
const autocompleteNameScope = mockAutocomplete(nockInstance, autocompleteNameUrl, true, [], 2);
|
|
208
|
-
const searchDelayScope = mockSetting(nockInstance, 'autosearch_delay', 0);
|
|
209
|
-
const autoSearchScope = mockSetting(nockInstance, 'autosearch_while_typing');
|
|
210
205
|
|
|
211
206
|
const cvFiltersScope = nockInstance
|
|
212
207
|
.get(cvFilterRulesPath)
|
|
@@ -231,7 +226,9 @@ test('Can edit filter rules', async (done) => {
|
|
|
231
226
|
}),
|
|
232
227
|
});
|
|
233
228
|
|
|
234
|
-
const {
|
|
229
|
+
const {
|
|
230
|
+
queryByText, getAllByLabelText, getByLabelText,
|
|
231
|
+
} =
|
|
235
232
|
renderWithRedux(
|
|
236
233
|
withCVRoute(<CVContainerImageFilterContent filterId={195} details={details} />),
|
|
237
234
|
renderOptions,
|
|
@@ -258,7 +255,9 @@ test('Can edit filter rules', async (done) => {
|
|
|
258
255
|
expect(getByLabelText('add_edit_filter_rule')).toHaveAttribute('aria-disabled', 'false');
|
|
259
256
|
});
|
|
260
257
|
|
|
261
|
-
|
|
258
|
+
const searchInput = getAllByLabelText('Search input')[1];
|
|
259
|
+
searchInput.focus();
|
|
260
|
+
fireEvent.change(searchInput, { target: { value: 'changed-name' } });
|
|
262
261
|
fireEvent.submit(getByLabelText('add_edit_filter_rule'));
|
|
263
262
|
|
|
264
263
|
await patientlyWaitFor(() => {
|
|
@@ -266,8 +265,6 @@ test('Can edit filter rules', async (done) => {
|
|
|
266
265
|
});
|
|
267
266
|
|
|
268
267
|
assertNockRequest(autocompleteScope);
|
|
269
|
-
assertNockRequest(searchDelayScope);
|
|
270
|
-
assertNockRequest(autoSearchScope);
|
|
271
268
|
assertNockRequest(cvFiltersScope);
|
|
272
269
|
assertNockRequest(cvFilterAddScope);
|
|
273
270
|
assertNockRequest(autocompleteNameScope);
|
|
@@ -284,8 +281,6 @@ test('Shows call-to-action when there are no filter rules', async (done) => {
|
|
|
284
281
|
2,
|
|
285
282
|
);
|
|
286
283
|
const autocompleteNameScope = mockAutocomplete(nockInstance, autocompleteNameUrl, true, [], 2);
|
|
287
|
-
const searchDelayScope = mockSetting(nockInstance, 'autosearch_delay', 0);
|
|
288
|
-
const autoSearchScope = mockSetting(nockInstance, 'autosearch_while_typing');
|
|
289
284
|
const cvFiltersScope = nockInstance
|
|
290
285
|
.get(cvFilterRulesPath)
|
|
291
286
|
.times(2)
|
|
@@ -302,13 +297,11 @@ test('Shows call-to-action when there are no filter rules', async (done) => {
|
|
|
302
297
|
await patientlyWaitFor(() => expect(queryByLabelText('add_filter_rule_empty_state')).toBeInTheDocument());
|
|
303
298
|
fireEvent.click(queryByLabelText('add_filter_rule_empty_state'));
|
|
304
299
|
await patientlyWaitFor(() => {
|
|
305
|
-
expect(getAllByLabelText('
|
|
300
|
+
expect(getAllByLabelText('Search input')[0]).toBeInTheDocument();
|
|
306
301
|
});
|
|
307
302
|
|
|
308
303
|
assertNockRequest(autocompleteScope);
|
|
309
304
|
assertNockRequest(autocompleteNameScope);
|
|
310
|
-
assertNockRequest(searchDelayScope);
|
|
311
|
-
assertNockRequest(autoSearchScope);
|
|
312
305
|
assertNockRequest(cvFiltersScope, done);
|
|
313
306
|
act(done);
|
|
314
307
|
});
|
|
@@ -8,7 +8,6 @@ import {
|
|
|
8
8
|
nockInstance,
|
|
9
9
|
assertNockRequest,
|
|
10
10
|
mockAutocomplete,
|
|
11
|
-
mockSetting,
|
|
12
11
|
} from '../../../../../test-utils/nockWrapper';
|
|
13
12
|
import api from '../../../../../services/api';
|
|
14
13
|
import cvFilterDetails from './cvPackageFilterDetail.fixtures.json';
|
|
@@ -163,8 +162,6 @@ test('Can add package rules to filter in a self-closing modal', async (done) =>
|
|
|
163
162
|
nockInstance, autocompleteArchUrl, true,
|
|
164
163
|
undefined, 2,
|
|
165
164
|
);
|
|
166
|
-
const searchDelayScope = mockSetting(nockInstance, 'autosearch_delay', 0, 3);
|
|
167
|
-
const autoSearchScope = mockSetting(nockInstance, 'autosearch_while_typing', undefined, 3);
|
|
168
165
|
|
|
169
166
|
const cvFiltersScope = nockInstance
|
|
170
167
|
.get(cvFiltersPath)
|
|
@@ -214,20 +211,22 @@ test('Can add package rules to filter in a self-closing modal', async (done) =>
|
|
|
214
211
|
});
|
|
215
212
|
getByLabelText('add_rpm_rule').click();
|
|
216
213
|
await patientlyWaitFor(() => {
|
|
217
|
-
expect(getAllByLabelText('
|
|
218
|
-
expect(getAllByLabelText('
|
|
214
|
+
expect(getAllByLabelText('Search input')[0]).toBeInTheDocument();
|
|
215
|
+
expect(getAllByLabelText('Search input')[1]).toBeInTheDocument();
|
|
219
216
|
expect(getByLabelText('add_package_filter_rule')).toBeInTheDocument();
|
|
220
217
|
});
|
|
221
|
-
|
|
222
|
-
|
|
218
|
+
const nameSearchInput = getAllByLabelText('Search input')[1];
|
|
219
|
+
const archSearchInput = getAllByLabelText('Search input')[2];
|
|
220
|
+
nameSearchInput.focus();
|
|
221
|
+
fireEvent.change(nameSearchInput, { target: { value: 'elephant' } });
|
|
222
|
+
archSearchInput.focus();
|
|
223
|
+
fireEvent.change(archSearchInput, { target: { value: 'noarch' } });
|
|
223
224
|
fireEvent.submit(getByLabelText('add_package_filter_rule'));
|
|
224
225
|
|
|
225
226
|
await patientlyWaitFor(() => {
|
|
226
227
|
expect(queryByText('Add rule')).not.toBeInTheDocument();
|
|
227
228
|
});
|
|
228
229
|
assertNockRequest(autocompleteScope);
|
|
229
|
-
assertNockRequest(searchDelayScope);
|
|
230
|
-
assertNockRequest(autoSearchScope);
|
|
231
230
|
assertNockRequest(autocompleteNameScope);
|
|
232
231
|
assertNockRequest(autocompleteArchScope);
|
|
233
232
|
assertNockRequest(cvFiltersScope);
|
|
@@ -241,8 +240,6 @@ test('Can add package rules to filter in a self-closing modal', async (done) =>
|
|
|
241
240
|
test('Remove rpm filter rule in a self-closing modal', async (done) => {
|
|
242
241
|
const { name: cvFilterName } = cvFilterDetails;
|
|
243
242
|
const autocompleteScope = mockAutocomplete(nockInstance, autocompleteUrl);
|
|
244
|
-
const searchDelayScope = mockSetting(nockInstance, 'autosearch_delay', 0);
|
|
245
|
-
const autoSearchScope = mockSetting(nockInstance, 'autosearch_while_typing');
|
|
246
243
|
|
|
247
244
|
const cvFiltersScope = nockInstance
|
|
248
245
|
.get(cvFiltersPath)
|
|
@@ -289,8 +286,6 @@ test('Remove rpm filter rule in a self-closing modal', async (done) => {
|
|
|
289
286
|
});
|
|
290
287
|
|
|
291
288
|
assertNockRequest(autocompleteScope);
|
|
292
|
-
assertNockRequest(searchDelayScope);
|
|
293
|
-
assertNockRequest(autoSearchScope);
|
|
294
289
|
assertNockRequest(cvFiltersScope);
|
|
295
290
|
assertNockRequest(cvFilterDetailsScope);
|
|
296
291
|
assertNockRequest(cvPackageFilterRulesScope);
|
|
@@ -310,8 +305,6 @@ test('Edit rpm filter rule in a self-closing modal', async (done) => {
|
|
|
310
305
|
nockInstance, autocompleteArchUrl, true,
|
|
311
306
|
undefined, 2,
|
|
312
307
|
);
|
|
313
|
-
const searchDelayScope = mockSetting(nockInstance, 'autosearch_delay', 0, 3);
|
|
314
|
-
const autoSearchScope = mockSetting(nockInstance, 'autosearch_while_typing', undefined, 3);
|
|
315
308
|
const cvFiltersScope = nockInstance
|
|
316
309
|
.get(cvFiltersPath)
|
|
317
310
|
.times(2)
|
|
@@ -366,8 +359,6 @@ test('Edit rpm filter rule in a self-closing modal', async (done) => {
|
|
|
366
359
|
});
|
|
367
360
|
|
|
368
361
|
assertNockRequest(autocompleteScope);
|
|
369
|
-
assertNockRequest(searchDelayScope);
|
|
370
|
-
assertNockRequest(autoSearchScope);
|
|
371
362
|
assertNockRequest(autocompleteNameScope);
|
|
372
363
|
assertNockRequest(autocompleteArchScope);
|
|
373
364
|
assertNockRequest(cvFiltersScope);
|
|
@@ -381,8 +372,6 @@ test('Shows call-to-action when there are no RPM filters', async (done) => {
|
|
|
381
372
|
const autocompleteScope = mockAutocomplete(nockInstance, autocompleteUrl);
|
|
382
373
|
const autocompleteNameScope = mockAutocomplete(nockInstance, autocompleteNameUrl);
|
|
383
374
|
const autocompleteArchScope = mockAutocomplete(nockInstance, autocompleteArchUrl);
|
|
384
|
-
const searchDelayScope = mockSetting(nockInstance, 'autosearch_delay', 0, 3);
|
|
385
|
-
const autoSearchScope = mockSetting(nockInstance, 'autosearch_while_typing', undefined, 3);
|
|
386
375
|
const cvFilterDetailScope = nockInstance
|
|
387
376
|
.get(cvFilterDetailsPath)
|
|
388
377
|
.query(true)
|
|
@@ -397,7 +386,7 @@ test('Shows call-to-action when there are no RPM filters', async (done) => {
|
|
|
397
386
|
.query(true)
|
|
398
387
|
.reply(200, emptyCVPackageFilterRules);
|
|
399
388
|
const {
|
|
400
|
-
queryByLabelText,
|
|
389
|
+
queryByLabelText, queryByText, getAllByLabelText,
|
|
401
390
|
} =
|
|
402
391
|
renderWithRedux(withCVRoute(<ContentViewFilterDetails
|
|
403
392
|
cvId={1}
|
|
@@ -408,7 +397,7 @@ test('Shows call-to-action when there are no RPM filters', async (done) => {
|
|
|
408
397
|
fireEvent.click(queryByLabelText('add_rpm_rule_empty_state'));
|
|
409
398
|
|
|
410
399
|
await patientlyWaitFor(() => {
|
|
411
|
-
expect(getAllByLabelText('
|
|
400
|
+
expect(getAllByLabelText('Search input')[0]).toBeInTheDocument();
|
|
412
401
|
expect(queryByText('Cancel')).toBeInTheDocument();
|
|
413
402
|
});
|
|
414
403
|
fireEvent.click(queryByText('Cancel'));
|
|
@@ -418,8 +407,6 @@ test('Shows call-to-action when there are no RPM filters', async (done) => {
|
|
|
418
407
|
assertNockRequest(autocompleteNameScope);
|
|
419
408
|
assertNockRequest(autocompleteArchScope);
|
|
420
409
|
assertNockRequest(autocompleteScope);
|
|
421
|
-
assertNockRequest(searchDelayScope);
|
|
422
|
-
assertNockRequest(autoSearchScope);
|
|
423
410
|
assertNockRequest(cvFiltersScope);
|
|
424
411
|
assertNockRequest(cvFilterDetailScope);
|
|
425
412
|
assertNockRequest(cvPackageFilterRulesScope);
|
data/webpack/scenes/ContentViews/Details/Filters/__tests__/ContentViewPackageGroupFilter.test.js
CHANGED
|
@@ -46,8 +46,6 @@ const renderOptions = {
|
|
|
46
46
|
|
|
47
47
|
const withCVRoute = component => <Route path="/content_views/:id([0-9]+)#/filters/:filterId([0-9]+)">{component}</Route>;
|
|
48
48
|
|
|
49
|
-
jest.mock('../../../../../components/Search', () => () => 'mocked!');
|
|
50
|
-
|
|
51
49
|
test('Can enable and disable add filter button', async (done) => {
|
|
52
50
|
const autocompleteScope = mockAutocomplete(nockInstance, autocompleteUrl, autocompleteQuery);
|
|
53
51
|
const { name: cvFilterName } = cvFilterDetails;
|